<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet href="https://codedchords.dev/feed_style.xsl" type="text/xsl"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
    <tabi:metadata xmlns:tabi="https://github.com/welpo/tabi">
        <tabi:base_url>https:&#x2F;&#x2F;codedchords.dev</tabi:base_url>
        <tabi:separator>
            •
        </tabi:separator>
        <tabi:about_feeds>This is a web feed, also known as an Atom feed. Subscribe by copying the URL from the address bar into your newsreader. Visit About Feeds to learn more and get started. It&#x27;s free.</tabi:about_feeds>
        <tabi:visit_the_site>Visit website</tabi:visit_the_site>
        <tabi:recent_posts>Recent posts</tabi:recent_posts>
        <tabi:last_updated_on>Updated on $DATE</tabi:last_updated_on>
        <tabi:default_theme></tabi:default_theme>
        <tabi:post_listing_date>date</tabi:post_listing_date>
        <tabi:current_section>Tech</tabi:current_section>
    </tabi:metadata><title>Coded Chords - Tech</title>
        <subtitle>A personal blog</subtitle>
    <link href="https://codedchords.dev/tags/tech/atom.xml" rel="self" type="application/atom+xml"/>
    <link href="https://codedchords.dev/tags/tech/" rel="alternate" type="text/html"/>
    <generator uri="https://www.getzola.org/">Zola</generator><updated>2026-07-16T00:00:00+00:00</updated><id>https://codedchords.dev/tags/tech/atom.xml</id><entry xml:lang="en">
        <title>AWS障害でPayPayが利用不可に フランクフルトの一AZが世界に波及</title>
        <published>2026-07-16T00:00:00+00:00</published>
        <updated>2026-07-16T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2026/07/aws-cloudfront-outage-paypay/" type="text/html"/>
        <id>https://codedchords.dev/blog/2026/07/aws-cloudfront-outage-paypay/</id>
        
            <content type="html">&lt;!-- textlint-disable --&gt;
&lt;img
  src=&quot;https:&amp;#x2F;&amp;#x2F;codedchords.dev&amp;#x2F;blog&amp;#x2F;2026&amp;#x2F;07&amp;#x2F;aws-cloudfront-outage-paypay&amp;#x2F;cover.webp?h=74290d2761d8a8cd538e&quot;
  alt=&quot;Cover&quot; width=&quot;1376&quot; height=&quot;768&quot; loading=&quot;lazy&quot;
&#x2F;&gt;&lt;!-- textlint-enable --&gt;
&lt;details&gt;
&lt;summary&gt;Table of Contents&lt;&#x2F;summary&gt;
&lt;!-- toc --&gt;
&lt;&#x2F;details&gt;
&lt;p&gt;2026年7月16日17時40分頃、Amazon Web Services(AWS)のCDNサービス「Amazon CloudFront」で大規模な障害が発生しました。日本の決済サービス「PayPay」をはじめ、ニコニコ生放送、はてなブログ、noteなど多数のサービスに影響が出ています。PayPayではアプリの読み込みや決済処理ができなくなり、公式サイトや障害情報ページ自体にもアクセスできない状態に陥りました。障害発生後、PayPay側は決済手段として「オフライン支払いモード」への切り替えを利用者に案内しています。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;障害詳細&quot;&gt;障害詳細&lt;&#x2F;h2&gt;
&lt;p&gt;発生時刻は日本時間で2026年7月16日17時40分頃(AWS公式の調査開始は現地時間1:44 AM PDT)です。症状としては、CloudFront経由のアクセスで504 Gateway Timeoutなどの5xxエラーが多発しました。日本国内ではPayPay、ニコニコ生放送、はてなブログ、noteなどが影響を受けたほか、日本、スペイン、ドイツ、オーストラリア、スウェーデン、フランス、米国、英国など世界9か国39都市以上で障害が報告されています。&lt;&#x2F;p&gt;
&lt;p&gt;日本国内で影響を受けた主なサービスは次のとおりです。&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;サービス&lt;&#x2F;th&gt;&lt;th&gt;影響内容&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;PayPay&lt;&#x2F;td&gt;&lt;td&gt;アプリの読み込み・決済処理不可、公式サイト・障害情報ページも接続不可&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;ニコニコ生放送&lt;&#x2F;td&gt;&lt;td&gt;接続しにくい状態&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;はてなブログ&lt;&#x2F;td&gt;&lt;td&gt;接続しにくい状態&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;note&lt;&#x2F;td&gt;&lt;td&gt;接続しにくい状態&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;AWSのステータスサイトによると、障害の直接的な引き金はCloudFrontの「VPC Origins」機能でした。VPC Originsは、CloudFrontから顧客のプライベートVPC内にあるバックエンドリソースへ安全に接続するための機能で、これを利用している顧客側でエラーが多発しました。一方、標準的なS3オリジンなど、VPC Originsを使わない構成は影響を受けていません。AWSは応急的な回避策として、VPC Originsを使わない構成に切り替えることでエラーを回避できるとアナウンスしています。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;一地域の障害が世界規模に広がった理由&quot;&gt;一地域の障害が世界規模に広がった理由&lt;&#x2F;h2&gt;
&lt;p&gt;今回の障害で興味深いのは、技術的な発生源が非常に局所的だった点です。障害の起点は、EU-CENTRAL-1(フランクフルト)リージョンの単一アベイラビリティゾーン「euc1-az2」に限定されていました。&lt;&#x2F;p&gt;
&lt;p&gt;つまり、物理的な不具合はドイツの1つのデータセンター群(AZ)内で起きたものにすぎません。しかし、CloudFrontはグローバルに分散した単一のCDNネットワークとしてVPC Origins接続を提供する仕組みになっているため、フランクフルトの一部で生じた問題が、世界中のエッジロケーション経由で各国のサービスへ波及する結果となりました。&lt;&#x2F;p&gt;
&lt;p&gt;これは、CDNのようにグローバルに一体運用されるインフラでは、1つのリージョンやAZの障害が地理的に無関係な地域にまで影響しうることを示す典型例といえます。東京リージョン自体には障害の原因はなく、あくまでフランクフルト発、世界巻き込み型の障害でした。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;障害を事前に防げたか&quot;&gt;障害を事前に防げたか&lt;&#x2F;h2&gt;
&lt;p&gt;クラウドを利用したシステム設計では、どのような機能であっても一時的に利用できなくなる可能性を前提に、二重化やフェイルオーバーの仕組みを組み込むのが一般的な考え方です。&lt;&#x2F;p&gt;
&lt;p&gt;今回の件で言えば、CDNをCloudFrontという単一のサービスに依存し、単一障害点になっていたことが技術的な問題点だったと考えられます。&lt;&#x2F;p&gt;
&lt;p&gt;しかし、CloudFrontは多くの技術者にとって自システムの外側に当たり前に存在するインフラという感覚に近く、これ自体が障害点になり得るという認識を持てていなかったのではないかと思います。&lt;&#x2F;p&gt;
&lt;p&gt;仮にその認識を持てていたとしても、実際に設計へ組み込むにはマルチCDN構成、例えばCloudflareなど別系統のCDNとの併用が必要になります。これはコストとのバランスから、多くの企業にとって現実的な選択肢とは言いにくいのが実情です。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;まとめ&quot;&gt;まとめ&lt;&#x2F;h2&gt;
&lt;p&gt;今回のPayPay障害は、PayPay自体のシステム不具合ではなく、利用しているAWS CloudFrontの障害が波及したものです。直接の原因はCloudFrontの「VPC Origins」機能における不具合で、発生源はフランクフルト(EU-CENTRAL-1)の単一AZでしたが、CloudFrontのグローバル構成により世界規模で影響が拡大しました。東京リージョン固有の問題ではなく、VPC Originsを使わないオリジン構成(S3など)は影響を受けていません。&lt;&#x2F;p&gt;
&lt;p&gt;大規模なグローバルCDNに依存するサービスが増える中、一地域の局所的な障害が世界中の決済・コンテンツサービスに連鎖する構造的リスクを改めて浮き彫りにした事例といえます。&lt;&#x2F;p&gt;
&lt;p&gt;このブログも以前は&lt;a href=&quot;https:&#x2F;&#x2F;codedchords.dev&#x2F;blog&#x2F;2026&#x2F;01&#x2F;blog-to-zola-aws-cleanup&#x2F;&quot;&gt;Amazon Amplify + CloudFrontで運用していました&lt;&#x2F;a&gt;が、現在はCloudflareに移行しているため今回の障害の影響は受けませんでした。ただし、CloudFrontとCloudflareはどちらも巨大なグローバルAnycast網であり、同種の相関障害リスク構造を持っています。実際、Cloudflare自体も過去に世界規模の障害を起こしています。今回無傷だったのはたまたまで、CDNの選定自体がこの種のリスクを下げるわけではありません。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;References&quot;&gt;References&lt;&#x2F;h2&gt;
&lt;!-- textlint-disable --&gt;
&lt;div class=&quot;references&quot;&gt;
    &lt;ul&gt;
&lt;li&gt;ITmedia NEWS.「AWSで障害 「CloudFront」世界規模で不調 PayPayに影響、noteやニコニコ生放送もつながりにくく」&lt;&#x2F;li&gt;
&lt;li&gt;ケータイ Watch.「PayPayの障害はAWSが原因、決済は「オフライン支払いモード」を」&lt;&#x2F;li&gt;
&lt;li&gt;BigGo ファイナンス.「PayPayで大規模障害、AWSのCDN不調が波及 公式サイトもダウン」&lt;&#x2F;li&gt;
&lt;li&gt;GIGAZINE.「AWSのCDNサービスで大規模障害発生、各種ウェブサイトに接続しにくい状態が発生」&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;note.com&#x2F;zephel01&#x2F;n&#x2F;n274043a396db?hl=en&quot;&gt;note - zephel01&lt;&#x2F;a&gt;. &quot;Summary of AWS (Mainly CloudFront) Outage (July 16, 2026)&quot;&lt;&#x2F;li&gt;
&lt;li&gt;Sunday Guardian Live.「AWS CloudFront Outage Today: Amazon Web Services Confirms Service Disruption as &#x27;5xx Errors&#x27; Hit Websites Across Multiple Regions」&lt;&#x2F;li&gt;
&lt;li&gt;The Nightly.「AWS outage update: CloudFront experience global outage, operation issue」&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;

&lt;&#x2F;div&gt;
&lt;!-- textlint-enable --&gt;
</content>
        <summary type="html">2026年7月16日、AWSのCDN「CloudFront」で障害が発生し、PayPayの決済やニコニコ生放送、はてなブログなど多数のサービスに影響が出ました。発生源はフランクフルトの単一AZという局所的な障害でしたが、なぜ日本を含む世界9か国に波及したのか、その仕組みを整理します。</summary>
        </entry><entry xml:lang="en">
        <title>技術文書用フォーマット AsciiDoc</title>
        <published>2026-07-10T05:00:00+09:00</published>
        <updated>2026-07-10T05:00:00+09:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2026/07/asciidoc/" type="text/html"/>
        <id>https://codedchords.dev/blog/2026/07/asciidoc/</id>
        
            <content type="html">&lt;!-- textlint-disable --&gt;
&lt;img
  src=&quot;https:&amp;#x2F;&amp;#x2F;codedchords.dev&amp;#x2F;blog&amp;#x2F;2026&amp;#x2F;07&amp;#x2F;asciidoc&amp;#x2F;cover.webp?h=2af306a0693c3ee09dbc&quot;
  alt=&quot;Cover&quot; width=&quot;1536&quot; height=&quot;864&quot; loading=&quot;lazy&quot;
&#x2F;&gt;&lt;!-- textlint-enable --&gt;
&lt;details&gt;
&lt;summary&gt;Table of Contents&lt;&#x2F;summary&gt;
&lt;!-- toc --&gt;
&lt;&#x2F;details&gt;
&lt;span id=&quot;continue-reading&quot;&gt;&lt;&#x2F;span&gt;
&lt;p&gt;AsciiDocで書かれたドキュメントを修正する必要があったので、
AsciiDoctorを導入しました。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;AsciiDocとは&quot;&gt;AsciiDocとは&lt;&#x2F;h2&gt;
&lt;p&gt;AsciiDocは、2002年にStuart Rackham氏が開発したマークアップ言語です。
もともとはDocBook XMLを人間が書きやすい記法で表現するためのPython製ツールとして
誕生しました。プレーンテキストで書いた文書を、HTMLやPDF、EPUBなど複数の形式に
変換できる点が特徴です。&lt;&#x2F;p&gt;
&lt;p&gt;2013年にはRuby実装のAsciidoctorが登場し、現在ではこちらが主流の処理系となっています。
本記事でも、AsciiDocの処理系としてAsciidoctorを使用します。&lt;&#x2F;p&gt;
&lt;p&gt;2019年からはEclipse Foundation傘下の
AsciiDoc Working Groupによって言語仕様の標準化も進められており、
処理系間の互換性が高まりつつあります。&lt;&#x2F;p&gt;
&lt;p&gt;ただし、技術文書での採用率では明確にMarkdownが優位です。
技術文書作成者の主要フォーマットとしてMarkdownを使う割合が约65%とされ、デファクトスタンダードの地位にあります。学習コストの低さとツールの豊富さ、生成AIで扱う文書形式の標準となっていることが理由です。
実際にはAsciiDocは全体の採用率では大きく水を開けられています。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;MacへのAsciiDocの導入&quot;&gt;MacへのAsciiDocの導入&lt;&#x2F;h2&gt;
&lt;p&gt;AsciiDocの処理系としてAsciiDoctorを使用します。&lt;&#x2F;p&gt;
&lt;p&gt;ランタイムにRubyを使用するので、Rubyのインストールから行っています。
前提として、私の環境では
&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;mise.jdx.dev&quot;&gt;mise&lt;&#x2F;a&gt;で言語のバージョンを管理しています。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot; data-name=&quot;install.sh&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# Rubyのインストール&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;mise&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; use -g ruby@latest&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;gem&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; install asciidoctor asciidoctor-pdf asciidoctor-rouge&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;gem&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; install asciidoctor-pdf-cjk asciidoctor-diagram&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;AsciiDocのサンプル&quot;&gt;AsciiDocのサンプル&lt;&#x2F;h2&gt;
&lt;p&gt;似たようなマークアップ言語にMarkdownがありますが、
以下のような点でAsciiDocが優れているので作る文書の特性で
使い分けています。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;目次や表紙の生成が可能&lt;&#x2F;li&gt;
&lt;li&gt;細かいテーブルの表現が可能&lt;&#x2F;li&gt;
&lt;li&gt;ソースコードにシンタックスハイライトや吹き出しが使える&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;GitHubやGitLabでもネイティブでAsciiDocのレンダリングに対応しています。
始めからHTMLやPDFへの変換を意識して作られている点でも優れています。&lt;&#x2F;p&gt;
&lt;p&gt;次にサンプルを提示します。
Frontmatterを除くと、ソースのままでも読みやすい形式です。
特に今回はソースコードの解説だったので、以下の例ではソースコードへの解説を追記する例となっています。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;asciidoc&quot; data-name=&quot;sample.adoc&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-markup z-heading z-heading-0 z-asciidoc&quot;&gt;= サンプル&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt;toc&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; left&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt;toc-title&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; 目次&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt;toclevel&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; 4&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt;imagesdir&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; images&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt;figure-caption&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; 図&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt;chapter-signifier&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt;scripts&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; cjk&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt;pdf-theme&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; default-with-font-fallbacks&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt;doctype&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; book&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt;sectnumlevels&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; 4&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt;sectnums&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt;source-highlighter&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; rouge&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt;rouge-style&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; gruvbox&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-markup z-heading z-heading-1 z-asciidoc&quot;&gt;== Hello World&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;.hello.py&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;source&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt;python]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;----&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-function z-builtin z-python&quot;&gt;print&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;Hello World!&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;  &amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;1&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;i&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 3&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-control z-flow z-python&quot;&gt;if&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt; i&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; ==&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 1&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;             &amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;2&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-function z-builtin z-python&quot;&gt;  print&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;i = 1&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-control z-flow z-python&quot;&gt;elif&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt; i&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; ==&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 2&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-function z-builtin z-python&quot;&gt;  print&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;i = 2&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-control z-flow z-python&quot;&gt;elif&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt; i&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; ==&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 3&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-function z-builtin z-python&quot;&gt;  print&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;i = 3&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-control z-flow z-python&quot;&gt;else&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-function z-builtin z-python&quot;&gt;  print&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;i = 4&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;----&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;&amp;lt;1&amp;gt; やっぱりサンプルといえばコレな&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;&amp;lt;2&amp;gt; IF文です！&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;AsciiDocを変換する&quot;&gt;AsciiDocを変換する&lt;&#x2F;h2&gt;
&lt;p&gt;作成したAsciiDocのソースは以下のコマンドでHTMLやPDFに変換します。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot; data-name=&quot;convert.sh&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# HTMLの生成&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;asciidoctor&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; --backend html5 sample.adoc -o sample.html&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# PDFの生成&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;asciidoctor-pdf&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; sample.adoc -o sample.pdf&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;以下が生成したサンプルです。&lt;&#x2F;p&gt;
&lt;!-- textlint-disable --&gt;
&lt;img
  src=&quot;https:&amp;#x2F;&amp;#x2F;codedchords.dev&amp;#x2F;blog&amp;#x2F;2026&amp;#x2F;07&amp;#x2F;asciidoc&amp;#x2F;sample.webp?h=aa551a1eddeb908ee3e0&quot;
  alt=&quot;AsciiDoc生成結果&quot; width=&quot;983&quot; height=&quot;572&quot; loading=&quot;lazy&quot;
&#x2F;&gt;&lt;!-- textlint-enable --&gt;
&lt;h2 id=&quot;まとめ&quot;&gt;まとめ&lt;&#x2F;h2&gt;
&lt;p&gt;AsciiDocは
Markdownと似ているので混乱する部分もありますが、
Markdownよりやりたいことをストレートに書けると思います。&lt;&#x2F;p&gt;
&lt;p&gt;サンプルのようにAsciiDocのメタデータにいろいろ記載すると生成するスタイルも
変更できるのでいろんな文章に柔軟に対応できると思います。&lt;&#x2F;p&gt;
</content>
        <summary type="html">ソースコードの解説を含む技術文書を書く必要があり、AsciiDocとその処理系Asciidoctorを
導入しました。Markdownが標準となった今あえてAsciiDocを選ぶ理由と、
Mac環境での導入手順、実際の変換サンプルを紹介します。
</summary>
        </entry><entry xml:lang="en">
        <title>CloudflareのAI対策見直しとAIエージェント対応度診断</title>
        <published>2026-07-08T00:00:00+00:00</published>
        <updated>2026-07-08T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2026/07/cloudflare-ai-access-review/" type="text/html"/>
        <id>https://codedchords.dev/blog/2026/07/cloudflare-ai-access-review/</id>
        
            <content type="html">&lt;!-- textlint-disable --&gt;
&lt;img
  src=&quot;https:&amp;#x2F;&amp;#x2F;codedchords.dev&amp;#x2F;blog&amp;#x2F;2026&amp;#x2F;07&amp;#x2F;cloudflare-ai-access-review&amp;#x2F;cover.webp?h=be4593eef9e356ff784e&quot;
  alt=&quot;Cover&quot; width=&quot;1536&quot; height=&quot;864&quot; loading=&quot;lazy&quot;
&#x2F;&gt;&lt;!-- textlint-enable --&gt;
&lt;details&gt;
&lt;summary&gt;Table of Contents&lt;&#x2F;summary&gt;
&lt;!-- toc --&gt;
&lt;&#x2F;details&gt;
&lt;p&gt;2026年2月、&lt;a href=&quot;https:&#x2F;&#x2F;codedchords.dev&#x2F;blog&#x2F;2026&#x2F;02&#x2F;cloudflare-benefits&#x2F;&quot;&gt;Cloudflareへ移転した際の記事&lt;&#x2F;a&gt;で、AI学習クローラー対策としてContent Signals Policy、Block AI bots、AI Labyrinthという3層構成を紹介しました。あれから4か月、AIによるアクセスの重要性はさらに増しています。改めてこのブログのCloudflare設定を見直すとともに、Cloudflareが新しく公開したAgent Readinessスキャナーで「AIエージェントへの対応度」を診断してみました。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;Managed_robots.txtまわりを再確認する&quot;&gt;Managed robots.txtまわりを再確認する&lt;&#x2F;h2&gt;
&lt;p&gt;まず、AI Crawl Controlのダッシュボードを一通り確認しました。&lt;&#x2F;p&gt;
&lt;p&gt;Block AI training botsは「Block on all pages」のままで変更していません。このブログのコンテンツはCC BY-NC-ND 4.0(非営利・改変禁止)で公開しているので、商用LLMの学習データとして使われることは元々ライセンスの意図と衝突します。学習目的のクローラーは全ページで拒否するのが一貫した方針です。&lt;&#x2F;p&gt;
&lt;p&gt;Content Signalsでは、Managed robots.txtをオンにしています。&lt;&#x2F;p&gt;
&lt;p&gt;AI Crawl ControlのCrawlers一覧では、クローラーごとの許可&#x2F;ブロックを個別に確認しました。&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;カテゴリ&lt;&#x2F;th&gt;&lt;th&gt;例&lt;&#x2F;th&gt;&lt;th&gt;設定&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;AI Crawler(学習用)&lt;&#x2F;td&gt;&lt;td&gt;GPTBot、ClaudeBot、Bytespider、Amazonbot、TikTok Spider、Meta-ExternalAgent&lt;&#x2F;td&gt;&lt;td&gt;Block&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;AI Search &#x2F; AI Assistant&lt;&#x2F;td&gt;&lt;td&gt;Applebot、PerplexityBot、ChatGPT-User&lt;&#x2F;td&gt;&lt;td&gt;Allow&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Search Engine Crawler&lt;&#x2F;td&gt;&lt;td&gt;Googlebot、BingBot&lt;&#x2F;td&gt;&lt;td&gt;Allow&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;Crawlers一覧の分類も、学習目的のクローラーを拒否するという方針のとおりでした。あわせてAI Labyrinth(クロールルールを無視するボットに偽コンテンツを読ませるハニーポット機能、Beta)も確認しましたが、2月から変わらずONのままでした。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;「混在クローラー」という新しい論点&quot;&gt;「混在クローラー」という新しい論点&lt;&#x2F;h2&gt;
&lt;p&gt;今回の見直しで、2月時点にはなかった変化に気づきました。レガシー機能「Block AI bots」の設定画面に、次のような予告が表示されていたのです。&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;On September 15, mixed-purpose crawlers that are used both for search indexing and for training AI will be included in blocking AI training.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;ここで言う混在クローラーとは、前段のCrawlers一覧でSearch Engine CrawlerやAI Searchに分類し、学習とは無関係としてAllowにしていたGooglebot、Applebot、BingBotのことです。検索とAI学習を1回のクロールで同時に行うため両者を切り分けられず、学習ブロックを選んでいるサイトでは最も制限の強いルールを適用する、というのが実質的な立場だと考えられます。そのままでは検索エンジン経由の流入もAI検索・AIアシスタント経由の露出も失うため、「Mixed purpose crawlers will continue to be allowed」を選び、混在クローラーは引き続き許可する設定にしました。&lt;&#x2F;p&gt;
&lt;p&gt;レガシー機能は9月15日に廃止され、後継の「Configure AI bot policies」に一本化されます。こちらはボットを3種類に分類し、それぞれ個別にAllow&#x2F;Blockを選べる形になっていました。&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;分類&lt;&#x2F;th&gt;&lt;th&gt;説明&lt;&#x2F;th&gt;&lt;th&gt;設定&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;Search&lt;&#x2F;td&gt;&lt;td&gt;検索エンジンのインデックス用ボット&lt;&#x2F;td&gt;&lt;td&gt;Allow(Recommended)&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Agent&lt;&#x2F;td&gt;&lt;td&gt;ユーザーの質問への回答生成のために参照するボット&lt;&#x2F;td&gt;&lt;td&gt;Allow(Recommended)&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Training&lt;&#x2F;td&gt;&lt;td&gt;AI学習用にコンテンツをスクレイピングするボット&lt;&#x2F;td&gt;&lt;td&gt;Block(Recommended値はBlock on pages with ads)&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;Trainingだけ、広告のないこのブログの事情に合わせて推奨値の「Block on pages with ads」から「Block」に変更しました。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;AIエージェント対応度を診断してみた&quot;&gt;AIエージェント対応度を診断してみた&lt;&#x2F;h2&gt;
&lt;p&gt;Cloudflareは&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;isitagentready.com&#x2F;&quot;&gt;isitagentready.com&lt;&#x2F;a&gt;という無料の診断ツールを公開しています。&lt;&#x2F;p&gt;
&lt;p&gt;この診断ツールでは、サイトのAIエージェントへの対応度(Agent Readiness)を診断してくれます。&lt;&#x2F;p&gt;
&lt;p&gt;このブログのURLでスキャンしたところ、次のようなものでした。&lt;&#x2F;p&gt;
&lt;!-- textlint-disable --&gt;
&lt;figure&gt;&lt;img
  src=&quot;https:&amp;#x2F;&amp;#x2F;codedchords.dev&amp;#x2F;blog&amp;#x2F;2026&amp;#x2F;07&amp;#x2F;cloudflare-ai-access-review&amp;#x2F;agent-readiness.webp?h=634fa8b7fd82807af8a4&quot;
  alt=&quot;Agent Readiness&quot; width=&quot;1472&quot; height=&quot;1486&quot; loading=&quot;lazy&quot;
&#x2F;&gt;
&lt;figcaption&gt;当サイトのAgent Readiness&lt;&#x2F;figcaption&gt;
&lt;&#x2F;figure&gt;&lt;!-- textlint-enable --&gt;
&lt;h3 id=&quot;個人ブログサイトでは該当しない項目&quot;&gt;個人ブログサイトでは該当しない項目&lt;&#x2F;h3&gt;
&lt;p&gt;改善項目として、10個の指摘を受けました。
ただし、10個のうち6個はいずれも「稼働しているAPIやエージェントサービスがあること」を前提にした指摘でした。&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;指摘&lt;&#x2F;th&gt;&lt;th&gt;規格&lt;&#x2F;th&gt;&lt;th&gt;該当しない理由&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;DNS for AI Discovery (DNS-AID)&lt;&#x2F;td&gt;&lt;td&gt;IETFドラフト、Linux Foundation 2026年発表&lt;&#x2F;td&gt;&lt;td&gt;他のAIエージェントから発見・接続されるエージェントサービス(チャットボット、MCPサーバー等)を運用していない&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;API Catalog&lt;&#x2F;td&gt;&lt;td&gt;RFC 9727&lt;&#x2F;td&gt;&lt;td&gt;カタログ化すべきAPIが存在しない&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;OAuth&#x2F;OIDC discovery metadata&lt;&#x2F;td&gt;&lt;td&gt;RFC 8414 等&lt;&#x2F;td&gt;&lt;td&gt;認証保護されたAPIや会員機能がない&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;OAuth Protected Resource Metadata&lt;&#x2F;td&gt;&lt;td&gt;RFC 9728&lt;&#x2F;td&gt;&lt;td&gt;同上&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;auth.md&lt;&#x2F;td&gt;&lt;td&gt;WorkOS提唱&lt;&#x2F;td&gt;&lt;td&gt;OAuth Protected Resource Metadataを前提とする、同上の理由&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;MCP Server Card&lt;&#x2F;td&gt;&lt;td&gt;SEP-1649(標準化進行中)&lt;&#x2F;td&gt;&lt;td&gt;MCPサーバーを運用していない&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;このブログは静的コンテンツを配信するだけのサイトで、APIやエージェント向けサービスは一切運用していません。この種の指摘は、SaaSやEC、API提供事業者向けのチェックリストとしては妥当ですが、個人ブログにはそもそも対象が存在しませんでした。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;対応した項目&quot;&gt;対応した項目&lt;&#x2F;h3&gt;
&lt;p&gt;「ホームページにLink response header(RFC 8288)がない」という指摘もありました。ツールの提案は&lt;code&gt;rel=&quot;api-catalog&quot;&lt;&#x2F;code&gt;や&lt;code&gt;rel=&quot;service-doc&quot;&lt;&#x2F;code&gt;でAPIカタログやAPI仕様書を指すというものでしたが、このブログにAPIはないので、この提案どおりに実装しても意味がありません。&lt;&#x2F;p&gt;
&lt;p&gt;代わりに、Linkヘッダーの仕組み自体はこのブログでも使い道があると考え、次の2つを指すヘッダーを追加しました。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;plain&quot; data-name=&quot;static&#x2F;_headers&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  Link: &amp;lt;&#x2F;license&#x2F;&amp;gt;; rel=&amp;quot;license&amp;quot;, &amp;lt;&#x2F;atom.xml&amp;gt;; rel=&amp;quot;alternate&amp;quot;; type=&amp;quot;application&#x2F;atom+xml&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;code&gt;rel=&quot;license&quot;&lt;&#x2F;code&gt;はIANA登録済みの正式なrelationで、CC BY-NC-ND 4.0を明記したライセンスページ(&lt;code&gt;&#x2F;license&#x2F;&lt;&#x2F;code&gt;)をAIエージェントが機械的に検出できるようにします。学習ボットのブロックと合わせて、コンテンツの利用条件を多層的に伝える形になりました。&lt;code&gt;rel=&quot;alternate&quot;&lt;&#x2F;code&gt;はZolaが生成するAtomフィード(&lt;code&gt;&#x2F;atom.xml&lt;&#x2F;code&gt;)へのリンクで、フィードの発見性を高めます。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;対応を見送った項目&quot;&gt;対応を見送った項目&lt;&#x2F;h3&gt;
&lt;p&gt;残る3個は、対応自体は可能でも今回は見送りました。&lt;&#x2F;p&gt;
&lt;p&gt;Markdown for Agentsは、&lt;code&gt;Accept: text&#x2F;markdown&lt;&#x2F;code&gt;のリクエストにHTMLの代わりにMarkdownを返す機能です。CloudflareのAI Crawl Control上では確認できましたが、Proプラン以上限定(2026年7月時点で月$20〜25)のため、Freeプランの現状ではロックされていました。個人ブログの一機能としてはコストに見合わないと判断し、見送りました。&lt;&#x2F;p&gt;
&lt;p&gt;WebMCPは、ブラウザ内蔵のAIエージェントに&lt;code&gt;navigator.modelContext.provideContext()&lt;&#x2F;code&gt;でサイトの操作(検索など)を直接公開する仕組みです。現状はEarly Preview Program参加者限定の実験段階で、一般のブラウザではまだ有効化されていません。このブログの操作対象もpagefindによる検索程度で薄く、標準化が進んだ段階で再検討することにしました。&lt;&#x2F;p&gt;
&lt;p&gt;Agent Skills discovery indexは、&lt;code&gt;&#x2F;.well-known&#x2F;agent-skills&#x2F;index.json&lt;&#x2F;code&gt;にサイト固有の作業手順(SKILL.md)を公開する仕組みです。コンテンツサイト向けの想定用途は「文章校正」「カテゴリ分類の提案」といった編集アシスタント業務で、これは既に自分のClaude Code環境でローカルに完結しています。v0.2.0のドラフト段階でエコシステムの普及状況も未検証なため、こちらも見送りとしました。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;まとめ&quot;&gt;まとめ&lt;&#x2F;h2&gt;
&lt;p&gt;Agent Readinessスキャンの10個の指摘を並べてみると、その多くはAPIやSaaS、エージェント向けサービスを運用している事業者を想定したチェックリストだと分かりました。静的な個人ブログにとって本当に意味のある「AI対応」は、実は範囲が絞られます。当サイトでの結論は次のとおりです。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;CC BY-NC-NDライセンスの意図に沿って、学習目的のクローラーは技術的にブロックする&lt;&#x2F;li&gt;
&lt;li&gt;robots.txtのContent Signalsとライセンスページへの&lt;code&gt;rel=&quot;license&quot;&lt;&#x2F;code&gt;で、利用条件を機械可読な形でも表明する&lt;&#x2F;li&gt;
&lt;li&gt;検索エンジンやAI回答エンジンからの参照は妨げず、露出の機会は残す&lt;&#x2F;li&gt;
&lt;li&gt;WebMCPやAgent Skillsのようなドラフト段階の規格には、実際に普及するまで様子見の姿勢を崩さない&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;2月の記事で組んだ多層防御の骨格は変わっていませんが、Cloudflare側の仕様変更(混在クローラーの扱い)に合わせて設定を追随させ、Agent Readinessという新しい物差しで一度棚卸しをしたことで、このブログのAI対応の現在地を再確認できました。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;References&quot;&gt;References&lt;&#x2F;h2&gt;
&lt;!-- textlint-disable --&gt;
&lt;div class=&quot;references&quot;&gt;
    &lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;blog.cloudflare.com&#x2F;content-signals-policy&#x2F;&quot;&gt;Cloudflare&lt;&#x2F;a&gt;. &quot;Giving users choice with Cloudflare&#x27;s new Content Signals Policy&quot;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;developers.cloudflare.com&#x2F;bots&#x2F;additional-configurations&#x2F;managed-robots-txt&#x2F;&quot;&gt;Cloudflare&lt;&#x2F;a&gt;. &quot;robots.txt setting&quot;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;blog.cloudflare.com&#x2F;content-independence-day-ai-options&#x2F;&quot;&gt;Cloudflare&lt;&#x2F;a&gt;. &quot;Your site, your rules: new AI traffic options for all customers&quot;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;blog.cloudflare.com&#x2F;agent-readiness&#x2F;&quot;&gt;Cloudflare&lt;&#x2F;a&gt;. &quot;Introducing the Agent Readiness score&quot;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.cloudflare.com&#x2F;plans&#x2F;pro&#x2F;&quot;&gt;Cloudflare&lt;&#x2F;a&gt;. &quot;Pro Plan Overview&quot;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.ietf.org&#x2F;archive&#x2F;id&#x2F;draft-mozleywilliams-dnsop-dnsaid-01.html&quot;&gt;IETF&lt;&#x2F;a&gt;. &quot;DNS for AI Discovery&quot;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;dns-aid.org&#x2F;&quot;&gt;DNS-AID&lt;&#x2F;a&gt;. &quot;AI Agent Discovery via DNS&quot;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.rfc-editor.org&#x2F;rfc&#x2F;rfc9727&quot;&gt;IETF&lt;&#x2F;a&gt;. &quot;RFC 9727: The api-catalog Well-Known URI and Link Relation Type&quot;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.rfc-editor.org&#x2F;rfc&#x2F;rfc8288&quot;&gt;IETF&lt;&#x2F;a&gt;. &quot;RFC 8288: Web Linking&quot;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;workos.com&#x2F;auth-md&quot;&gt;WorkOS&lt;&#x2F;a&gt;. &quot;auth.md — Open Protocol for Agent Registration&quot;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;modelcontextprotocol&#x2F;modelcontextprotocol&#x2F;pull&#x2F;2127&quot;&gt;Model Context Protocol&lt;&#x2F;a&gt;. &quot;MCP Server Card (SEP-1649)&quot;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;cloudflare&#x2F;agent-skills-discovery-rfc&quot;&gt;Cloudflare&lt;&#x2F;a&gt;. &quot;Agent Skills Discovery RFC&quot;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;agentskills.io&#x2F;&quot;&gt;Agent Skills&lt;&#x2F;a&gt;. &quot;Agent Skills&quot;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;developer.chrome.com&#x2F;blog&#x2F;webmcp-epp&quot;&gt;Chrome Developers&lt;&#x2F;a&gt;. &quot;WebMCP Early Preview Program&quot;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;

&lt;&#x2F;div&gt;
&lt;!-- textlint-enable --&gt;
</content>
        <summary type="html">2026年2月に整えたCloudflareのAIボット対策を4か月ぶりに見直しました。検索とAI学習を兼ねる「混在クローラー」を9月15日からブロック対象に含めるという仕様変更や、Agent Readinessスキャンで受けた10個の指摘を、個人ブログの視点で整理します。</summary>
        </entry><entry xml:lang="en">
        <title>メッセージングアプリの匿名性考察</title>
        <published>2026-07-01T10:00:00+09:00</published>
        <updated>2026-07-01T10:00:00+09:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2026/07/messenger-anonymity/" type="text/html"/>
        <id>https://codedchords.dev/blog/2026/07/messenger-anonymity/</id>
        
            <content type="html">&lt;!-- textlint-disable --&gt;
&lt;img
  src=&quot;https:&amp;#x2F;&amp;#x2F;codedchords.dev&amp;#x2F;blog&amp;#x2F;2026&amp;#x2F;07&amp;#x2F;messenger-anonymity&amp;#x2F;cover.webp?h=c60e5fcb30b3118d869c&quot;
  alt=&quot;Cover&quot; width=&quot;1536&quot; height=&quot;864&quot; loading=&quot;lazy&quot;
&#x2F;&gt;&lt;!-- textlint-enable --&gt;
&lt;details&gt;
&lt;summary&gt;Table of Contents&lt;&#x2F;summary&gt;
&lt;!-- toc --&gt;
&lt;&#x2F;details&gt;
&lt;p&gt;Threema GmbH（以下、Threema社）の公式ブログに「&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;threema.com&#x2F;en&#x2F;blog&#x2F;anonymity-at-the-system-level-the-ultimate-privacy-protection&quot;&gt;システムレベルの匿名性についての記事&lt;&#x2F;a&gt;」という記事が投稿されました。&lt;&#x2F;p&gt;
&lt;p&gt;メッセージングアプリの匿名性について論じています。以前、市川の強盗傷害事件をきっかけに&lt;a href=&quot;https:&#x2F;&#x2F;codedchords.dev&#x2F;blog&#x2F;2024&#x2F;10&#x2F;modern-messaging-apps&#x2F;&quot;&gt;暗号化やメタデータで機能比較した記事&lt;&#x2F;a&gt;を書きましたが、匿名性という観点はなかったのでこの記事を参考に解説したいと思います。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;メッセージングアプリの匿名性について&quot;&gt;メッセージングアプリの匿名性について&lt;&#x2F;h2&gt;
&lt;p&gt;Threema社の技術記事では、匿名性を二種類に分けています。&lt;&#x2F;p&gt;
&lt;dl&gt;
&lt;dt&gt;水平的匿名性&lt;&#x2F;dt&gt;
&lt;dd&gt;会話の相手に対する匿名性です。ユーザー名だけで連絡先を交換できれば、相手は電話番号や本名を知りません。対等な利用者どうしの間で成り立ちます。&lt;&#x2F;dd&gt;
&lt;dt&gt;垂直的匿名性&lt;&#x2F;dt&gt;
&lt;dd&gt;サービス運営者に対する匿名性です。登録時に電話番号やメールアドレスを渡していなければ、運営は身元を特定する手がかりを持ちません。利用者とサービスという上下の関係で成り立ちます。&lt;&#x2F;dd&gt;
&lt;&#x2F;dl&gt;
&lt;p&gt;Threema社は、ユーザー名機能で水平的匿名性は広まったものの、プライバシー保護で本当に重要なのは垂直的匿名性であり、これはセキュリティにおけるエンドツーエンド暗号化に相当する基盤だと主張します。あくまで同社の枠組みですが、この二軸はアプリを見比べる土台として使えます。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;垂直的匿名性の重要性について&quot;&gt;垂直的匿名性の重要性について&lt;&#x2F;h2&gt;
&lt;p&gt;なぜ運営に対する匿名性がそれほど問題になるのでしょうか。&lt;&#x2F;p&gt;
&lt;p&gt;メッセージングアプリでは、登録時に電話番号やメールアドレスを要求するものがあります。&lt;&#x2F;p&gt;
&lt;p&gt;ユーザー名で連絡先を交換できるサービスでも、相手にこうした個人情報を見せずに済むだけで、登録の段階では運営に渡しています。
電話番号やメールアドレスは本人確認や他サービスの登録にも使われる、生活に密着した識別子です。
運営がこれを保持していれば、別々の文脈で集めた情報を同一人物に結びつける手がかりとして使えてしまいます。&lt;&#x2F;p&gt;
&lt;p&gt;この紐付けは、広告で収益を上げるサービスでは特に意味を持ちます。利用者の行動を束ねてプロフィールを作るほど広告の精度が上がるので、複数の情報源を統合する動機がもともと働きます。電話番号やメールアドレスのような確実な識別子があれば、その統合は格段にやりやすくなります。メッセージの中身が暗号化されていても、誰がいつ誰と連絡したかというメタデータや、それを個人に結びつける識別子までは覆い隠せません。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;メッセージングアプリの匿名性の比較&quot;&gt;メッセージングアプリの匿名性の比較&lt;&#x2F;h2&gt;
&lt;p&gt;ここまでの軸で、私が知る範囲の主要なアプリを並べてみます。&lt;&#x2F;p&gt;
&lt;p&gt;暗号化の強さと、運営に対する匿名性は別物だという点に注目してください。暗号化の対応範囲やメタデータ収集、法執行機関への開示といった機能面の詳しい比較は&lt;a href=&quot;https:&#x2F;&#x2F;codedchords.dev&#x2F;blog&#x2F;2024&#x2F;10&#x2F;modern-messaging-apps&#x2F;&quot;&gt;前回の記事&lt;&#x2F;a&gt;にまとめたので、ここでは匿名性の軸に絞ります。&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;アプリ&lt;&#x2F;th&gt;&lt;th&gt;登録時に必要な個人情報&lt;&#x2F;th&gt;&lt;th&gt;運営に対する匿名性&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;LINE&lt;&#x2F;td&gt;&lt;td&gt;電話番号&lt;&#x2F;td&gt;&lt;td&gt;なし&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;WhatsApp&lt;&#x2F;td&gt;&lt;td&gt;電話番号&lt;&#x2F;td&gt;&lt;td&gt;なし&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;iMessage&lt;&#x2F;td&gt;&lt;td&gt;電話番号または Apple Account&lt;&#x2F;td&gt;&lt;td&gt;なし&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Signal&lt;&#x2F;td&gt;&lt;td&gt;電話番号&lt;&#x2F;td&gt;&lt;td&gt;なし&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Element &#x2F; Matrix&lt;&#x2F;td&gt;&lt;td&gt;なし（メールは任意）&lt;&#x2F;td&gt;&lt;td&gt;サーバー次第&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Threema&lt;&#x2F;td&gt;&lt;td&gt;なし&lt;&#x2F;td&gt;&lt;td&gt;運営は満たすと主張&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Session&lt;&#x2F;td&gt;&lt;td&gt;なし&lt;&#x2F;td&gt;&lt;td&gt;高い&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;SimpleX&lt;&#x2F;td&gt;&lt;td&gt;なし&lt;&#x2F;td&gt;&lt;td&gt;最も高い部類&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;国内利用者の多いLINEは、もう少し細かく見ておきます。LINEのメッセージはLetter Sealingと呼ぶ技術で暗号化されていますが、50人を超えるグループトーク、グループ音声・ビデオ通話、LINEミーティング、アルバム、ノートは対象外で、通信路のTLS暗号化にとどまります。
この範囲は運営が技術的に中身へアクセスし得ます。そして匿名性の面では、登録に電話番号が必須なので運営に対する匿名性は持ちません。自治体などが市民の申請にLINEを使
うケースが増えていますし、たまに企業でも業務で使用しているケースを見かけます。セキュリティ意識の低さには驚きます。&lt;&#x2F;p&gt;
&lt;p&gt;WhatsAppとiMessageも、垂直的匿名性はありません。メッセージの暗号化に対応していますが、登録にはWhatsAppが電話番号、iMessageが電話番号かApple Accountを必要とします。この時点で運営に対する匿名性は持ちません。
特にWhatsAppを運営するMeta社は広告を収入源としているので
、個人情報に関連したメタデータを収集してグループ内の他社と共有している可能性があります。
中身は守られても、誰といつ繋がったかまでは隠せません。&lt;&#x2F;p&gt;
&lt;!-- textlint-disable --&gt;
&lt;aside data-position=&quot;right&quot;&gt;
    &lt;p&gt;ただし、Signalのメタ情報の電話番号、登録日、最終接続日のみ。&lt;&#x2F;p&gt;

&lt;&#x2F;aside&gt;
&lt;!-- textlint-enable --&gt;
&lt;p&gt;暗号化に強いというイメージのSignalも垂直的匿名性はありません。
ユーザー名機能が2024年に加わり、電話番号を教えないまま連絡できるようになりました(水平的匿名性)が、
アカウントの作成には今も電話番号が必須です。
Signalを運営するのはSignal Foundationという非営利団体ですが、拠点はカリフォルニア州です。
つまり米国の管轄下なので、米国の捜査機関の要求があれば開示義務があります。&lt;&#x2F;p&gt;
&lt;p&gt;ElementはMatrixというオープンなプロトコルの上に作られています。登録に必要なのは、選んだサーバー上のユーザー名とパスワードだけで、電話番号は要りません。メールアドレスはパスワード再設定用に任意で登録でき、サーバーによっては不正利用対策で求められることもあります。利用者はmatrix.orgのような公開サーバーを選んで登録するのが一般的で、自前でサーバーを立てることもできます。運営に対する匿名性は、結局どのサーバーを信頼するかに依存します。&lt;&#x2F;p&gt;
&lt;p&gt;結局、垂直的匿名性を保持しているのは、Threema、Session、SimpleXのみです。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;垂直的匿名性の代償&quot;&gt;垂直的匿名性の代償&lt;&#x2F;h2&gt;
&lt;p&gt;垂直的匿名性の仕組みと、その代わりに払う利便性のコストを見ておきます。&lt;&#x2F;p&gt;
&lt;p&gt;Threemaは電話番号やメールアドレスを必要とせず、アカウントはランダムに割り当てられたThreema IDだけで機能します。
ユーザーはThreema IDを交換しメッセージの送受信を行ないます。
伝えるのはThreema IDのみなので、運営や相手に身元を明かさずに通信できます。
Threemaを使用していることすら秘匿する為にGoogle Playなどに依存せずThreemaを入手・購入できる手段も提供しています。
Threema IDはThreema社により管理されており、「IDが誰か」はThreema社に把握されませんが「いつ・どのIDと通信したか」は
論理的にはThreema社で把握可能です。ただし、Threema社は広告やトラッキングを行なわないというポリシーを持ち、収益源を買い切り課金に置いています。&lt;&#x2F;p&gt;
&lt;p&gt;SimpleXは、利用者を識別する固定IDを一切持たない設計です。電話番号やユーザー名はもちろん、ランダムなIDすら使いません。仕組みは一方向のメッセージキューで、接続ごとに送信用と受信用の別々のキューを持ち、通常はそれぞれ別のサーバーを経由します。
サーバーから見えるのは不透明なキューへの孤立した配送だけで、送信者と受信者を結びつけられません。サーバー同士も通信せず、配送が済んだメッセージは保存しません。&lt;&#x2F;p&gt;
&lt;p&gt;SessionはもともとSignalのフォークとして始まりました。電話番号やメールなどの個人データも不要で、ランダムなSession IDという66文字程度の公開鍵をアカウントのIDとして使います。メッセージは多数の有志ノードからなるオニオン型のネットワークを経由し、どのノードも送信者と受信者の両方を知ることはありません。運営は2024年10月に、暗号化技術への規制圧力を背景としてオーストラリアからスイスへ拠点を移し、現在はスイスのSession Technology Foundationが運営しています。コードはQuarkslabによる独立監査を受けています。SimpleXとの違いは、Sessionが永続的なアカウントのIDを持つ点です。&lt;&#x2F;p&gt;
&lt;p&gt;これらの高い匿名性には、現実的な代償が伴います。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;いずれも、相手に直接リンクやQRコード、IDを渡さなければ会話を始められない&lt;&#x2F;li&gt;
&lt;li&gt;従って、電話番号やユーザー名で気軽に相手を見つけることはできず、なんらかの方法で相手と直接これらの情報を交換する必要がある&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;一番問題になるのは、相手も同じアプリを入れている必要があるところでしょう。
いずれもマイナーなアプリなので、匿名性のために連絡相手の数と手軽さを大きく差し出すことになります。
この利便性の低さは、日常使いを考えるうえで無視できないトレードオフです。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;メッセージングアプリについて私の選択&quot;&gt;メッセージングアプリについて私の選択&lt;&#x2F;h2&gt;
&lt;p&gt;ここまで匿名性の強さで並べてきましたが、強ければ強いほどよい、という話ではありません。匿名性がどれだけ効くかは、相手があなたの身元を知っているかどうかで変わります。&lt;&#x2F;p&gt;
&lt;p&gt;私は以下のように考えています。&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;関係&lt;&#x2F;th&gt;&lt;th&gt;説明&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;家族&lt;&#x2F;td&gt;&lt;td&gt;当然対面しており、インストールするアプリも管理可能。機微なメッセージ交換もあり&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;友人&lt;&#x2F;td&gt;&lt;td&gt;対面しているが、アプリの管理は困難。機微なメッセージ交換は限定的&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;他人&lt;&#x2F;td&gt;&lt;td&gt;必ずしも対面していない。アプリの管理は不能。機微なメッセージはなし&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;このように考えると、家族とは水平的匿名性は不要で垂直的匿名性が必要です。
前回の記事でも軽く触れましたが、私自身は家族との連絡用にThreemaを選んでいます。
SimpleXやSessionでもよいのですが、かなり以前からThreemaを使用しており、特に問題もないために使用を続けています。&lt;&#x2F;p&gt;
&lt;p&gt;友人も同様です。知り合いなので水平的匿名性は不要ですが、垂直的匿名性は必要です。
しかし、現実的には垂直的匿名性を実現するために、先に記述した「代償」のため友人に対応するアプリを導入してもらうことは困難です。
そのため諦めて必要な場合は、友人にはメールかSMSでのコンタクトを依頼しています。暗号化、匿名性は放棄すると言うことです。
LINEなどを使っていると「じゃ、LINEで」と言われるので、私はLINEなどのアプリは使わずインストールさえしていません。&lt;&#x2F;p&gt;
&lt;p&gt;ネットで知り合ったような他人については、どちらの匿名性も重要だと思います。
しかし、私は、匿名のままネットで知り合った相手とメッセージングアプリを使って通信するようなニーズはないので無視します。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;まとめ&quot;&gt;まとめ&lt;&#x2F;h2&gt;
&lt;p&gt;LINE・WhatsApp・iMessage・Signalなど主要なメッセージングアプリは、暗号化や水平的匿名性は実装されていますが、
垂直的匿名性は担保されていません。LINEなど「なりすまし防止、復旧、法令遵守」などを理由に電話番号への紐付けを強化しています。
自治体などでLINEを使用するケースが多いようですが、あれは個人特定を行政として放棄しているとしか思えません。&lt;&#x2F;p&gt;
&lt;p&gt;私にとって必要なのは垂直的匿名性です。メッセージの中身が暗号化されていても、運営に身元や「誰といつ通信したか」を握られては、プライバシーを守ったことになりません。
一方、相手に対しても名乗らない水平的匿名性は、私個人にはほとんど必要ありません。&lt;&#x2F;p&gt;
&lt;p&gt;両方の匿名性を保てるのは、Threema・Session・SimpleXの3つです。&lt;&#x2F;p&gt;
&lt;!-- textlint-disable --&gt;
&lt;aside data-position=&quot;right&quot;&gt;
    &lt;p&gt;米国報道機関ではSignalが使用されているケースが多いようです。&lt;&#x2F;p&gt;

&lt;&#x2F;aside&gt;
&lt;!-- textlint-enable --&gt;
&lt;p&gt;両方の匿名性が必要なのは、相手や運営に身元を伏せたまま連絡したい場面だけです。
こうしたニーズは犯罪目的での使用を想起するかもしれませんが、内部告発や情報提供など正当な目的のためにも必要です。
米国では報道機関が情報提供の窓口としてメッセージングアプリの宛先などを公開しています。
日本ではこうした使い方はほとんど根づいておらず、全く遅れています。&lt;&#x2F;p&gt;
&lt;p&gt;大切なのは、自分がどちらの匿名性を必要とするのかを見極めることです。垂直的匿名性はほとんどの人に効きますが、水平的匿名性まで求めるかは人によって大きく変わります。私自身は、身元を隠す必要のない家族との連絡に、垂直的匿名性を保ちつつ扱いやすいThreemaを使っています。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;References&quot;&gt;References&lt;&#x2F;h2&gt;
&lt;!-- textlint-disable --&gt;
&lt;div class=&quot;references&quot;&gt;
    &lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;threema.com&#x2F;en&#x2F;blog&#x2F;anonymity-at-the-system-level-the-ultimate-privacy-protection&quot;&gt;Threema&lt;&#x2F;a&gt;. &quot;Anonymity at the System Level: The Ultimate Privacy Protection&quot;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;threema.ch&#x2F;en&#x2F;blog&#x2F;posts&#x2F;news-alleged-weaknesses-statement&quot;&gt;Threema&lt;&#x2F;a&gt;. &quot;Statement on ETH Findings&quot;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;breakingthe3ma.app&#x2F;&quot;&gt;ETH Zurich Applied Cryptography Group&lt;&#x2F;a&gt;. &quot;Three Lessons from Threema&quot;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;signal.org&#x2F;blog&#x2F;phone-number-privacy-usernames&#x2F;&quot;&gt;Signal&lt;&#x2F;a&gt;. &quot;Keep your phone number private with Signal usernames&quot;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;signalfoundation.org&#x2F;en&#x2F;&quot;&gt;Signal Foundation&lt;&#x2F;a&gt;. &quot;Signal Foundation&quot;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;simplex.chat&#x2F;docs&#x2F;simplex.html&quot;&gt;SimpleX Chat&lt;&#x2F;a&gt;. &quot;How SimpleX works&quot;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;getsession.org&#x2F;blog&#x2F;introducing-the-session-technology-foundation&quot;&gt;Session&lt;&#x2F;a&gt;. &quot;Introducing the Session Technology Foundation&quot;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;getsession.org&#x2F;session-code-audit&quot;&gt;Session&lt;&#x2F;a&gt;. &quot;Session code audit by Quarkslab&quot;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;faq.whatsapp.com&#x2F;820124435853543&quot;&gt;WhatsApp Help Center&lt;&#x2F;a&gt;. &quot;About end-to-end encryption&quot;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;support.apple.com&#x2F;guide&#x2F;security&#x2F;imessage-security-overview-secd9764312f&#x2F;web&quot;&gt;Apple Support&lt;&#x2F;a&gt;. &quot;iMessage security overview&quot;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;docs.element.io&#x2F;latest&#x2F;element-support&#x2F;matrix-account-management&#x2F;creating-a-matrix-account&#x2F;&quot;&gt;Element&lt;&#x2F;a&gt;. &quot;Creating a Matrix Account&quot;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;help.line.me&#x2F;line&#x2F;smartphone&#x2F;categoryId&#x2F;20010067&#x2F;3&#x2F;pc&quot;&gt;LINE Help Center&lt;&#x2F;a&gt;. &quot;Letter Sealing&quot;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.lycorp.co.jp&#x2F;ja&#x2F;privacy-security&#x2F;security&#x2F;transparency&#x2F;encryption-report&#x2F;2025&#x2F;&quot;&gt;LINEヤフー&lt;&#x2F;a&gt;.「LINE暗号化状況レポート（2025年）」&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;

&lt;&#x2F;div&gt;
&lt;!-- textlint-enable --&gt;
</content>
        <summary type="html">Threema公式ブログに「システムレベルの匿名性」についての記事が公開されました。
日本ではLINEが主流で匿名性についての関心は薄いと思うので、その仕組みと重要性を解説してみました。
</summary>
        </entry><entry xml:lang="en">
        <title>pCloud DriveのmacOS Tahoe問題</title>
        <published>2026-06-27T10:00:00+09:00</published>
        <updated>2026-06-27T10:00:00+09:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2026/06/pcloud-tahoe-rclone/" type="text/html"/>
        <id>https://codedchords.dev/blog/2026/06/pcloud-tahoe-rclone/</id>
        
            <content type="html">&lt;!-- textlint-disable --&gt;
&lt;img
  src=&quot;https:&amp;#x2F;&amp;#x2F;codedchords.dev&amp;#x2F;blog&amp;#x2F;2026&amp;#x2F;06&amp;#x2F;pcloud-tahoe-rclone&amp;#x2F;cover.webp?h=705f04e088eabd5c42f6&quot;
  alt=&quot;Cover&quot; width=&quot;1536&quot; height=&quot;864&quot; loading=&quot;lazy&quot;
&#x2F;&gt;&lt;!-- textlint-enable --&gt;
&lt;details&gt;
&lt;summary&gt;Table of Contents&lt;&#x2F;summary&gt;
&lt;!-- toc --&gt;
&lt;&#x2F;details&gt;
&lt;p&gt;macOS Tahoe(macOS 26)に上げてから、pCloud Driveが起動するが機能しない状態となりました。
やっかいなのは、アプリ単体では済まず、うっかりpCloud Driveを開こうとするとキーボードが効かなくなるなどMac全体が一時的に不安定になる点です。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;pCloudとは&quot;&gt;pCloudとは&lt;&#x2F;h2&gt;
&lt;p&gt;pCloudは、スイスのpCloud AGが提供するクラウドストレージサービスです。買い切りの生涯プランがあること、ファイルを暗号化して預けられること、そしてアカウントを作ると無料枠から使い始められることで知られています。&lt;&#x2F;p&gt;
&lt;p&gt;Macで使う場合、もっとも手軽なのは公式のpCloud Driveアプリです。これはクラウド上のファイルを、ローカルの仮想ドライブ(&lt;code&gt;~&#x2F;pCloud Drive&lt;&#x2F;code&gt;)としてマウントして見せてくれます。Finderから普通のフォルダのように開けるので、クラウドを意識せずに使えるのが利点です。&lt;&#x2F;p&gt;
&lt;p&gt;一方で、この「仮想ドライブとして見せる」仕組みは、macOSのファイルシステム拡張に依存します。後述するように、ここがOSのアップデートで影響を受けやすい部分でもあります。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;macOS_Tahoeでの不具合&quot;&gt;macOS Tahoeでの不具合&lt;&#x2F;h2&gt;
&lt;p&gt;私の環境はApple SiliconのMacで、OSはTahoe(macOS 26)です。アップデート後、pCloud Driveが機能せず、開こうとするとOS全体の挙動が一時的に不安定になりました。&lt;&#x2F;p&gt;
&lt;p&gt;同様の現象が一般に報告されているか調べたところ、Tahoe環境での不具合報告が複数見つかりました。代表的なものは次の通りです。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;アップデート後に「Enable Disk(仮想ドライブのマウント)」が機能しない&lt;&#x2F;li&gt;
&lt;li&gt;メニューバーのアイコンが表示されない&lt;&#x2F;li&gt;
&lt;li&gt;ドライブは見えてもマウント・同期ができない&lt;&#x2F;li&gt;
&lt;li&gt;ドライブ有効化時に「outdated(古い)」と表示され有効化できない&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;これらはフォーラムでの報告であり、「同様の事例が存在する」ことの裏付けにはなりますが、原因や解決を断定する根拠にはなりません。pCloud公式が症状ごとの原因を断定して公表しているわけでもありません。そのため、ここから先に書く原因は、あくまで私の推測として読んでください。&lt;&#x2F;p&gt;
&lt;p&gt;pCloud Driveは、クラウドをローカルの仮想ドライブとして見せるために、ファイルシステム拡張(pCloudFS &#x2F; macFUSE)を使います。この低レベルの拡張がロードに失敗したり、カーネル側で引っかかったりすると、アプリ単体のクラッシュにとどまらず、OS全体の挙動に波及することがあります。私が遭遇した「開こうとすると全体が不安定」という症状は、このパターンと整合します。OSのメジャーアップデート直後は、こうした低レベル拡張の互換性が崩れやすく、不安定になりがちです。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;pCloud_Driveのアンインストール&quot;&gt;pCloud Driveのアンインストール&lt;&#x2F;h2&gt;
&lt;p&gt;macOS向けのpCloud DriveはApple Siliconになってから問題も多く、macOSの変更による影響も受けやすいのでうんざりしていました。&lt;&#x2F;p&gt;
&lt;p&gt;OS全体を巻き込んで不安定になるアプリの回復に時間をかけるより、他の方法に移行しpCloud Driveはアンインストールすることにしました。&lt;&#x2F;p&gt;
&lt;p&gt;アンインストールは次の2ステップが必要です。&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;ログイン項目からpCloud Driveを外してmacOSを再起動&lt;&#x2F;li&gt;
&lt;li&gt;pCloud Driveの削除&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;まずシステム設定 → 一般 → ログイン項目と機能拡張からpCloud Driveを外し、いったんmacOSを再起動して拡張の常駐を切ります。&lt;&#x2F;p&gt;
&lt;p&gt;次にアプリ本体を削除です。&lt;&#x2F;p&gt;
&lt;p&gt;手動で削除する場合は、pCloud Driveを完全終了(できればアプリ内でログアウト&#x2F;Unlink)してから、アプリ本体をゴミ箱へ移し、&lt;code&gt;~&#x2F;Library&lt;&#x2F;code&gt;配下の残骸を削除します。主な残骸は次の場所です。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot; data-name=&quot;leftovers.txt&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;~&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;&#x2F;Library&#x2F;Application Support&#x2F;pCloud&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;~&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;&#x2F;Library&#x2F;Application Support&#x2F;com.pcloud.pcloud.macos&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;~&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;&#x2F;Library&#x2F;Caches&#x2F;com.pcloud.pcloud.macos&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;~&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;&#x2F;Library&#x2F;Preferences&#x2F;com.pcloud.pcloud.macos.plist&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;私が実際に使ったのは、CLIのアンインストーラであるMole(&lt;code&gt;tw93&#x2F;Mole&lt;&#x2F;code&gt;)です。Homebrewで導入でき、コマンド名は&lt;code&gt;mo&lt;&#x2F;code&gt;になります。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot; data-name=&quot;install-mole.sh&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;brew&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; install mole&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;code&gt;mo uninstall&lt;&#x2F;code&gt;は、アプリ本体に加えて、launch agentやPreferences、Cachesといった関連ファイルもまとめて削除してくれます。安全のため、まず&lt;code&gt;--dry-run&lt;&#x2F;code&gt;で削除対象を確認してから本実行しました。対象アプリの正確な名前は&lt;code&gt;--list&lt;&#x2F;code&gt;で確認できます。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot; data-name=&quot;uninstall.sh&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;mo&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; uninstall --list&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;                   # mo uninstall が受け付ける正確なアプリ名を一覧表示&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;mo&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt; uninstall --dry-run &amp;quot;pCloud Drive&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;  # 削除対象を事前確認(変更は行わない)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;mo&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; uninstall&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;                           # 対話形式の一覧から pCloud Drive を選んで実行&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;引数なしの&lt;code&gt;mo uninstall&lt;&#x2F;code&gt;は対話形式のセレクタを開くので、一覧からpCloud Driveを選んで実行します。アプリ名を引数で渡せば、対話なしで直接アンインストールできます。削除されたファイルは既定でゴミ箱へ送られるため、必要なら復元できます。&lt;&#x2F;p&gt;
&lt;p&gt;Moleが消すのは、主にユーザーレベルの関連ファイルです。macOSにシステム拡張として登録された部分(pCloudFS &#x2F; システム拡張)は対象外になることがあります。通常はmacOSを再起動するとクリアされますが、残っていないかは次のコマンドで確認できます。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot; data-name=&quot;check-extensions.sh&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;systemextensionsctl&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; list&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;   # pCloud AG の拡張が残っていないか確認&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Mole自身も、macOS 15以降では一部の拡張系の権限エントリがアプリ削除後も残ること、そしてその種のリセットはグローバルかつリカバリモードを要するため自動では行わないことを、警告として明示しています。ツール任せにせず、最後は再起動と&lt;code&gt;systemextensionsctl list&lt;&#x2F;code&gt;での確認で締めるのが現実的です。私の環境では、ログイン項目から外して再起動したあとにアンインストールしたこともあり、最終的にpCloud AGの拡張は1つも残りませんでした。&lt;&#x2F;p&gt;
&lt;p&gt;なお、pCloud Driveアプリをアンインストールしても、pCloudアカウント自体は消えません。Web(my.pcloud.com)からファイルにはアクセスできますし、消えるのは有効化済みの同期設定とカスタム設定だけです。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;rcloneでの設定方法とメリット&quot;&gt;rcloneでの設定方法とメリット&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;rclone.org&#x2F;&quot;&gt;rclone&lt;&#x2F;a&gt;は、各種クラウドストレージをコマンドラインから統一的に扱えるツールです。以前「&lt;a href=&quot;https:&#x2F;&#x2F;codedchords.dev&#x2F;blog&#x2F;2026&#x2F;04&#x2F;rclone&#x2F;&quot;&gt;rcloneとS3ライフサイクルで作る個人データのコールドアーカイブ&lt;&#x2F;a&gt;」でAmazon S3を使った長期保管の構成をまとめましたが、pCloudもバックエンドとして公式にサポートされています。&lt;&#x2F;p&gt;
&lt;p&gt;設定は&lt;code&gt;rclone config&lt;&#x2F;code&gt;の対話で行います。ブラウザ認証を済ませると、設定ファイル&lt;code&gt;~&#x2F;.config&#x2F;rclone&#x2F;rclone.conf&lt;&#x2F;code&gt;が作られ、内容は次のようになります。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;toml&quot; data-name=&quot;rclone.conf&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;pcloud&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;type&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; pcloud&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;hostname&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; eapi.pcloud.com&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;token&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; {&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;&amp;quot;access_token&amp;quot;:&amp;quot;&amp;lt;rclone config の認証で自動生成されるアクセストークン&amp;gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;&amp;quot;token_type&amp;quot;:&amp;quot;bearer&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;&amp;quot;expiry&amp;quot;:&amp;quot;0001-01-01T00:00:00Z&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;ここで&lt;code&gt;token&lt;&#x2F;code&gt;は&lt;code&gt;rclone config&lt;&#x2F;code&gt;のOAuth認証で自動生成されるものです。手で書く必要はありませんし、アクセストークンそのものなので、他人に見せたりリポジトリにコミットしたりしないよう注意してください。この記事でも実際の値はプレースホルダに置き換えています。&lt;&#x2F;p&gt;
&lt;!-- textlint-disable --&gt;
&lt;aside data-position=&quot;right&quot;&gt;
    &lt;p&gt;私はプライバシーを重視しているので、ヨーロッパリージョン(&lt;code&gt;eapi.pcloud.com&lt;&#x2F;code&gt;)を使っています。&lt;&#x2F;p&gt;

&lt;&#x2F;aside&gt;
&lt;!-- textlint-enable --&gt;
&lt;p&gt;&lt;code&gt;hostname&lt;&#x2F;code&gt;はリージョンを指します。&lt;code&gt;eapi.pcloud.com&lt;&#x2F;code&gt;はヨーロッパリージョン、&lt;code&gt;api.pcloud.com&lt;&#x2F;code&gt;(デフォルト)は米国リージョンです。アカウントがヨーロッパリージョンの場合は、ここを&lt;code&gt;eapi.pcloud.com&lt;&#x2F;code&gt;に設定しておかないとトークンエラーになることがあります。通常はOAuth認証の過程で適切に設定されますが、うまくいかないときはこの値を疑ってください。&lt;&#x2F;p&gt;
&lt;p&gt;設定できたら、まずは中身が見えるか確認します。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot; data-name=&quot;verify.sh&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;rclone&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; lsd pcloud:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;                                # トップ階層のディレクトリ一覧&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;rclone&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; copy pcloud:My&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt;\ &lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;Pictures ~&#x2F;Downloads&#x2F;pics&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;  # 取り出し(ダウンロード)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;rclone&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; sync ~&#x2F;work pcloud:work&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;                    # ローカルからクラウドへ同期(送信)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Finderのようにフォルダとしてマウントしたい場合は&lt;code&gt;rclone mount&lt;&#x2F;code&gt;も使えますが、こちらはmacFUSEを必要とします。日常的なファイルの取り出しや同期は、マウントせずとも上記のコマンドだけで完結します。&lt;&#x2F;p&gt;
&lt;p&gt;pCloud Driveからrcloneへ寄せる利点は、大きく2つです。&lt;&#x2F;p&gt;
&lt;dl&gt;
&lt;dt&gt;macOSへの非依存&lt;&#x2F;dt&gt;
&lt;dd&gt;コマンドベースの転送(&lt;code&gt;copy&lt;&#x2F;code&gt;、&lt;code&gt;sync&lt;&#x2F;code&gt;、&lt;code&gt;lsd&lt;&#x2F;code&gt;、&lt;code&gt;cat&lt;&#x2F;code&gt;)はファイルシステム拡張を使わず、ユーザーランドだけで完結する。今回の不具合の原因だったpCloudFS &#x2F; macFUSEとは無縁で、OSのメジャーアップデートにも振り回されない。&lt;&#x2F;dd&gt;
&lt;dt&gt;CLIでの自動化&lt;&#x2F;dt&gt;
&lt;dd&gt;CLIとなることで、&lt;code&gt;launchd&lt;&#x2F;code&gt;やシェルスクリプトに組み込みが自由になる。バックアップや定期同期などを自動化して回せる。&lt;&#x2F;dd&gt;
&lt;&#x2F;dl&gt;
&lt;h2 id=&quot;pCloudのサービス継続性について&quot;&gt;pCloudのサービス継続性について&lt;&#x2F;h2&gt;
&lt;p&gt;ここで、pCloudというサービス自体の信頼性にも触れておきます。&lt;&#x2F;p&gt;
&lt;p&gt;pCloudの大きなウリは、一度の支払いで使い続けられる&lt;strong&gt;買い切り(Lifetime)プラン&lt;&#x2F;strong&gt;です。
ただし、その「Lifetime」が何を指すのかは、規約を読むと印象より限定的です。pCloudの利用規約は、買い切りプランの有効期間を「アカウント所有者の生存期間か99年のいずれか短い方」と定義しています。さらに「pCloudが事業を停止した場合、アカウントは終了し、サービスは提供されない」とも明記されています。買い切りは、永久でも、企業の存続から独立した保証でもありません。&lt;&#x2F;p&gt;
&lt;p&gt;そうなると運営元の規模が気になります。&lt;&#x2F;p&gt;
&lt;p&gt;pCloudを提供するpCloud AGはスイスの非上場企業で社員は数十人規模、外部資本を入れないブートストラップ経営です。
非上場企業のため正確な業績は外から分かりません。出回っている年商も10億円程度&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-1-1&quot;&gt;&lt;a href=&quot;#fn-1&quot;&gt;1&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;です。&lt;&#x2F;p&gt;
&lt;p&gt;pCloudサービスは設立から10年以上続き、ユーザーも2,000万を超えて伸びており、「経営が危ない」という状況ではなさそうです。&lt;&#x2F;p&gt;
&lt;p&gt;しかし、規模の小ささ自体が構造的な継続性リスクになります。買収や方針転換、大手との競争で、サービスの将来を一個人が見通すことはできません。また、規模の小ささが、今回の様な新しいmacOSへの対応の遅れの要因ともなっているかと思います。&lt;&#x2F;p&gt;
&lt;p&gt;だからこそ、買い切りだからと唯一の保管先にはせず、今回のrcloneのような別経路や、ローカル・別クラウドにもコピーを持っておくのが現実的だと考えています。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;まとめ&quot;&gt;まとめ&lt;&#x2F;h2&gt;
&lt;p&gt;macOS Tahoeとの互換性によるpCloud Drive不具合から、一旦rcloneに移行しました。&lt;&#x2F;p&gt;
&lt;p&gt;とはいえ、pCloud DriveはDropboxのSmart Syncのようにキャッシュだけのローカルに置く方式で便利なので、いつか安定したら戻りたいものです。&lt;&#x2F;p&gt;
&lt;p&gt;振り返ってみると、pCloudの2TBライフタイムを購入したのは2021年です。350ドル（当時のレート1ドル約109円で約38,200円）の一括払いでした。仮に、Dropbox Plusの2TBを使用していたとしたら、年額15,840円（税込）かかります。
2年半足らずで買い切りが追いつき、購入から約5年が経った今では、Dropboxなら累計8万円ほどかかっていた計算です。円で累計コストを並べると、その差がはっきりします。&lt;&#x2F;p&gt;
&lt;!-- textlint-disable --&gt;
&lt;img
  src=&quot;https:&amp;#x2F;&amp;#x2F;codedchords.dev&amp;#x2F;blog&amp;#x2F;2026&amp;#x2F;06&amp;#x2F;pcloud-tahoe-rclone&amp;#x2F;cost-comparison.svg?h=42f101b3b0d542a4bd8a&quot;
  alt=&quot;2TBストレージの累計コスト。pCloudは2021年に約38,200円の買い切り、Dropboxは年額15,840円で累計が増え、約2.4年でpCloudが有利になる。&quot; width=&quot;760&quot; height=&quot;440&quot; loading=&quot;lazy&quot;
&#x2F;&gt;&lt;!-- textlint-enable --&gt;
&lt;p&gt;あまりヘビーに依存せず上手に使っていきたいと思います。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;References&quot;&gt;References&lt;&#x2F;h2&gt;
&lt;!-- textlint-disable --&gt;
&lt;div class=&quot;references&quot;&gt;
    &lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.pcloud.com&#x2F;release-notes&#x2F;mac-os.html&quot;&gt;pCloud&lt;&#x2F;a&gt;. 「pCloud for macOS リリースノート」&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.pcloud.com&#x2F;ja&#x2F;help&#x2F;general-help-center&#x2F;what-if-i-uninstall-pcloud-from-my-computer&quot;&gt;pCloud&lt;&#x2F;a&gt;. 「コンピュータからpCloudをアンインストールするとどうなりますか」&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.pcloud.com&#x2F;terms_and_conditions.html&quot;&gt;pCloud&lt;&#x2F;a&gt;. &quot;Terms and Conditions&quot;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;support.apple.com&#x2F;en-us&#x2F;102610&quot;&gt;Apple Support&lt;&#x2F;a&gt;. &quot;Delete apps on your Mac&quot;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;rclone.org&#x2F;pcloud&#x2F;&quot;&gt;rclone&lt;&#x2F;a&gt;. &quot;pCloud backend documentation&quot;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;tw93&#x2F;mole&quot;&gt;Mole&lt;&#x2F;a&gt;. &quot;tw93&#x2F;Mole&quot;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;

&lt;&#x2F;div&gt;
&lt;!-- textlint-enable --&gt;
&lt;section class=&quot;footnotes&quot;&gt;
&lt;ol class=&quot;footnotes-list&quot;&gt;
&lt;li id=&quot;fn-1&quot;&gt;
&lt;p&gt;創業者の自己申告(約16.5億円)と第三者の推計(約6.6億円)で2倍以上の開きがあり、健全性を客観的に確かめる手段がありません。 &lt;a href=&quot;#fr-1-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;&#x2F;section&gt;
</content>
        <summary type="html">pCloudを長らく使用していますが、macOS TahoeにしてからpCloud Driveが機能せずMac全体が一時的に不安定になりました。
他のユーザーでも同様らしくアプリの改善は時間がかかりそうなので、別の方法を検討しました。
</summary>
        </entry><entry xml:lang="en">
        <title>GR IV Monochromeから始めるdarktable現像術</title>
        <published>2026-06-12T09:46:20+09:00</published>
        <updated>2026-06-12T09:46:20+09:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2026/06/darktable/" type="text/html"/>
        <id>https://codedchords.dev/blog/2026/06/darktable/</id>
        
            <content type="html">&lt;img
  src=&quot;https:&amp;#x2F;&amp;#x2F;codedchords.dev&amp;#x2F;blog&amp;#x2F;2026&amp;#x2F;06&amp;#x2F;darktable&amp;#x2F;cover.webp?h=5ba5325b60304352f0ab&quot;
  alt=&quot;Cover&quot; width=&quot;1536&quot; height=&quot;864&quot; loading=&quot;lazy&quot;
&#x2F;&gt;&lt;details&gt;
&lt;summary&gt;Table of Contents&lt;&#x2F;summary&gt;
&lt;!-- toc --&gt;
&lt;&#x2F;details&gt;
&lt;span id=&quot;continue-reading&quot;&gt;&lt;&#x2F;span&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;codedchords.dev&#x2F;blog&#x2F;2026&#x2F;05&#x2F;gr-iv-monochrome&#x2F;&quot;&gt;RICOH GR IV Monochrome&lt;&#x2F;a&gt; を手に入れました。モノクロ専用機です。買うべき理由や撮影時の設定は別記事にまとめましたが、本稿はその続きにあたります。このカメラを手にしたのを機に、長らく惰性で使ってきたRAW現像アプリを一度見直すことにしました。撮ったあとの工程、つまり選定の記録と、最終的に選んだdarktableをモノクロ前提でどう使っているかのメモです。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;RAW現像アプリの選定&quot;&gt;RAW現像アプリの選定&lt;&#x2F;h2&gt;
&lt;p&gt;これまで使ってきたのは、市川ソフトラボラトリーのSILKYPIXでした。ただ、選んで使い続けてきたというより惰性です。今回そのまま使えなかったのは、GR IV Monochromeに対応していないからです。SILKYPIXは未対応のカメラ・レンズのRAWファイルをそもそも開けません。加えてMac版はWindows版から数年遅れたまま放置されており、現像も遅いと、見直す理由はそろっていました。&lt;&#x2F;p&gt;
&lt;p&gt;候補としていちばん有力だったのはAdobeのLightroom Classicです。操作は直感的で非常に使いやすく、RAWファイルのライブラリ構成を自分で管理でき、Lightroomが勝手に干渉してこないのも気に入っています。ただし、使うには悪名高いAdobeのサブスクリプションが要ります。そこだけがどうしても引っかかりました。&lt;&#x2F;p&gt;
&lt;p&gt;結局、無料でありながら高機能なdarktableを使うことにしました。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;darktable&quot;&gt;darktable&lt;&#x2F;h2&gt;
&lt;p&gt;darktableは高機能なのですが、Lightroomのように機能が整理されておらず、最初は取っ付きにくいツールです。モジュールの数も多く、全部を理解しようとすると挫折します。そこで、モノクロ前提で本当に使うモジュールだけを絞り込みました。現像はおおむね次の順序で進めます。&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;lens correction&lt;&#x2F;code&gt;（必須）— Lensfunデータベースを使い、歪曲と周辺減光を補正する&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;exposure&lt;&#x2F;code&gt;（必須）— 主要被写体の中間調を適正にする(白飛び・黒つぶれは無視)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;sigmoid&lt;&#x2F;code&gt;（必須）— ダイナミックレンジを表示レンジへ圧縮する(filmic rgb &#x2F; agxでも可)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;denoise (profiled)&lt;&#x2F;code&gt;（オプション）— ノイズを抑える&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;rotate and perspective&lt;&#x2F;code&gt;（オプション）— 傾いた水平を出す(必要ならパースも整える)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;retouch&lt;&#x2F;code&gt;（オプション）— ゴミや不要物を消す&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;tone equalizer&lt;&#x2F;code&gt;（オプション）— 明暗の局所コントラストを足す&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;diffuse or sharpen&lt;&#x2F;code&gt;（オプション）— 仕上げにシャープ化する(旧来のsharpenでも可)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;crop&lt;&#x2F;code&gt;（オプション）— 最後に構図をトリミングする&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;この流れの前提になっているのが、darktableが標準で採るscene-referredワークフローです。これは、センサーが捉えた光の量(リニアな値)をできるだけそのまま保ったまま現像を進め、モニタ表示に合わせた明暗の調整は最後にまとめて行う、という考え方です。明るさの情報を途中で切り詰めず、広いダイナミックレンジのまま持ち越して、いちばん最後にトーンマッピング(&lt;code&gt;sigmoid&lt;&#x2F;code&gt; など)で表示レンジへ圧縮します。&lt;&#x2F;p&gt;
&lt;p&gt;この前提があるので、作業は自然と二段構えになります。&lt;code&gt;exposure&lt;&#x2F;code&gt; では主要被写体の中間調だけを合わせ、白飛び・黒つぶれはあえて気にしません。広い階調はあとで &lt;code&gt;sigmoid&lt;&#x2F;code&gt; がまとめて表示レンジに収めてくれるからです。本稿のモジュール選定も、この流れに沿っています。&lt;&#x2F;p&gt;
&lt;p&gt;なお、darktableのモジュールは画面に並んだ順ではなく、内部で決められたパイプライン順に適用されます。上の並びはそのパイプライン順ではなく、darktable公式マニュアルが薦める作業順(最初にlens correction、次に基礎となる露出とトーンマッピング、続いて各種補正、最後に構図の仕上げ)に沿っています。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;lens_correction&quot;&gt;lens correction&lt;&#x2F;h3&gt;
&lt;div class=&quot;module&quot;&gt;
  &lt;div class=&quot;module-image&quot;&gt;
    &lt;img
      src=&quot;https:&amp;#x2F;&amp;#x2F;codedchords.dev&amp;#x2F;blog&amp;#x2F;2026&amp;#x2F;06&amp;#x2F;darktable&amp;#x2F;lens-correction.webp?h=9a605267a178ab3f576b&quot;
      alt=&quot;darktableのlens correctionモジュール&quot; width=&quot;250&quot; height=&quot;298&quot;
      loading=&quot;lazy&quot;
    &#x2F;&gt;
  &lt;&#x2F;div&gt;
  &lt;div class=&quot;module-body&quot;&gt;

&lt;p&gt;&lt;code&gt;lens correction&lt;&#x2F;code&gt; を有効にすると、Lensfunデータベースを参照して歪曲と周辺減光を自動補正します。GRの単焦点にもわずかな樽型の歪曲と周辺減光があり、これをまず取り除いておきます。&lt;&#x2F;p&gt;


  &lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;p&gt;6月12日時点では、Lensfunの公式データベースにRICOH GR IV Monochromeはまだ登録されていません。ただしGR IV(カラー機)は登録済みで、Monochromeのレンズ(光学系)はGR IVとまったく同じです。違いはセンサー前のカラーフィルターの有無だけなので、補正すべき歪曲・周辺減光のデータは共通して使えます。&lt;&#x2F;p&gt;
&lt;p&gt;問題は、MonochromeがEXIFに記録するカメラ名がGR IVとは別の文字列で、公式データベースのGR IVエントリに自動マッチしないことだけです。そこで、ユーザー領域のLensfunデータベースにMonochrome用のカメラ定義を1つだけ追加し、マウントをGR IVと同じ &lt;code&gt;ricohGRIV&lt;&#x2F;code&gt; にして既存のレンズ補正データを流用します。&lt;&#x2F;p&gt;
&lt;p&gt;darktableは &lt;code&gt;~&#x2F;.local&#x2F;share&#x2F;lensfun&#x2F;&lt;&#x2F;code&gt; 配下に置いたXMLを読み込みます。ここは公式データベースの更新では上書きされない領域です。次のファイルを置きます。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;xml&quot; data-name=&quot;ricoh-gr-iv-monochrome.xml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;lensdatabase&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-other z-attribute-name&quot;&gt; version&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;1&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;  &amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;camera&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;    &amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;maker&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt;Ricoh Imaging Company, Ltd.&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;maker&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;    &amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;maker&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-other z-attribute-name&quot;&gt; lang&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;en&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt;Ricoh&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;maker&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;    &amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;model&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt;Ricoh GR IV Monochrome&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;model&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;    &amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;model&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-other z-attribute-name&quot;&gt; lang&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;en&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt;GR IV Monochrome&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;model&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;    &amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;mount&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt;ricohGRIV&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;mount&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;    &amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;cropfactor&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt;1.53&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;cropfactor&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;  &amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;camera&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;lensdatabase&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;code&gt;&amp;lt;model&amp;gt;&lt;&#x2F;code&gt; は実機がEXIFに書き込むモデル名と一致させる必要があります。手元の値は &lt;code&gt;exiftool&lt;&#x2F;code&gt; で確認できます。darktableを再起動すると、スクリーンショットのようにcamera欄へ「Ricoh, GR IV Monochrome」が現れ、lens欄にはGR IVの固定レンズ補正がそのまま当たります。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;exposure&quot;&gt;exposure&lt;&#x2F;h3&gt;
&lt;div class=&quot;module&quot;&gt;
  &lt;div class=&quot;module-image&quot;&gt;
    &lt;img
      src=&quot;https:&amp;#x2F;&amp;#x2F;codedchords.dev&amp;#x2F;blog&amp;#x2F;2026&amp;#x2F;06&amp;#x2F;darktable&amp;#x2F;exposure.webp?h=fd7c384738c3b196d9af&quot;
      alt=&quot;darktableのexposureモジュール&quot; width=&quot;256&quot; height=&quot;201&quot;
      loading=&quot;lazy&quot;
    &#x2F;&gt;
  &lt;&#x2F;div&gt;
  &lt;div class=&quot;module-body&quot;&gt;

&lt;p&gt;scene-referredワークフローの起点です。前述のとおり、ここでは主要被写体の中間調が適正になるよう露出だけを決め、白飛びや黒つぶれは気にしません。スライダーを動かして、見せたい部分の明るさを合わせます。&lt;&#x2F;p&gt;


  &lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;h3 id=&quot;sigmoid&quot;&gt;sigmoid&lt;&#x2F;h3&gt;
&lt;div class=&quot;module&quot;&gt;
  &lt;div class=&quot;module-image&quot;&gt;
    &lt;img
      src=&quot;https:&amp;#x2F;&amp;#x2F;codedchords.dev&amp;#x2F;blog&amp;#x2F;2026&amp;#x2F;06&amp;#x2F;darktable&amp;#x2F;sigmoid.webp?h=db2ce45fc3b8448c9066&quot;
      alt=&quot;darktableのsigmoidモジュール&quot; width=&quot;252&quot; height=&quot;583&quot;
      loading=&quot;lazy&quot;
    &#x2F;&gt;
  &lt;&#x2F;div&gt;
  &lt;div class=&quot;module-body&quot;&gt;

&lt;p&gt;scene-referredな広いダイナミックレンジを、モニタが表示できる範囲へ圧縮するトーンマッピングです。darktableではfilmic rgbやagxと同じ役割を担い、&lt;code&gt;sigmoid&lt;&#x2F;code&gt; はそのなかでも素直に効きます。基本はcontrastで圧縮の強さを、skewでシャドウ側とハイライト側のどちらを持ち上げるかを決めるだけです。モノクロではprimaries(色の扱い)の各パラメータは結果に影響しないので、触る必要はありません。&lt;&#x2F;p&gt;


  &lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;h3 id=&quot;denoise_(profiled)&quot;&gt;denoise (profiled)&lt;&#x2F;h3&gt;
&lt;div class=&quot;module&quot;&gt;
  &lt;div class=&quot;module-image&quot;&gt;
    &lt;img
      src=&quot;https:&amp;#x2F;&amp;#x2F;codedchords.dev&amp;#x2F;blog&amp;#x2F;2026&amp;#x2F;06&amp;#x2F;darktable&amp;#x2F;denoise.webp?h=c6328463a558aa0364cf&quot;
      alt=&quot;darktableのdenoise (profiled) モジュール&quot; width=&quot;256&quot; height=&quot;480&quot;
      loading=&quot;lazy&quot;
    &#x2F;&gt;
  &lt;&#x2F;div&gt;
  &lt;div class=&quot;module-body&quot;&gt;

&lt;p&gt;高感度で撮った暗所のカットなどで、輝度ノイズのザラつきが気になるなら使います。&lt;&#x2F;p&gt;
&lt;p&gt;センサーごとに測定されたノイズの統計プロファイルを参照してノイズを除去するモジュールです。モノクロは輝度ノイズがそのまま見えるぶん、ザラつきが目立ちやすいので、気になるカットで抑えます。低感度で破綻がなければ飛ばして構いません。&lt;&#x2F;p&gt;


  &lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;h3 id=&quot;rotate_and_perspective&quot;&gt;rotate and perspective&lt;&#x2F;h3&gt;
&lt;div class=&quot;module&quot;&gt;
  &lt;div class=&quot;module-image&quot;&gt;
    &lt;img
      src=&quot;https:&amp;#x2F;&amp;#x2F;codedchords.dev&amp;#x2F;blog&amp;#x2F;2026&amp;#x2F;06&amp;#x2F;darktable&amp;#x2F;rotate.webp?h=eb323d7a39ed70f7a0ba&quot;
      alt=&quot;darktableのrotate and perspectiveモジュール&quot; width=&quot;258&quot; height=&quot;152&quot;
      loading=&quot;lazy&quot;
    &#x2F;&gt;
  &lt;&#x2F;div&gt;
  &lt;div class=&quot;module-body&quot;&gt;

&lt;p&gt;水平が傾いてしまったカットや、建築物の垂直を立て直したいときに使います。GRはノーファインダー撮影が多く、水平も傾きやすいカメラです。&lt;&#x2F;p&gt;
&lt;p&gt;rotationスライダーで角度を調整するか、画像上で水平にしたい線をドラッグして指定すると、その線が水平(または垂直)になるよう自動で回転します。パースの崩れを直したいときは、隠れているlens shiftやshearのコントロールも使えますが、スナップ中心の用途なら水平出しだけで十分です。&lt;&#x2F;p&gt;


  &lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;h3 id=&quot;retouch&quot;&gt;retouch&lt;&#x2F;h3&gt;
&lt;div class=&quot;module&quot;&gt;
  &lt;div class=&quot;module-image&quot;&gt;
    &lt;img
      src=&quot;https:&amp;#x2F;&amp;#x2F;codedchords.dev&amp;#x2F;blog&amp;#x2F;2026&amp;#x2F;06&amp;#x2F;darktable&amp;#x2F;retouch.webp?h=ec2728a57881e7d84e54&quot;
      alt=&quot;darktableのretouchモジュール&quot; width=&quot;253&quot; height=&quot;285&quot;
      loading=&quot;lazy&quot;
    &#x2F;&gt;
  &lt;&#x2F;div&gt;
  &lt;div class=&quot;module-body&quot;&gt;

&lt;p&gt;センサーのゴミや、写り込んだ不要物が目立つときに使います。&lt;&#x2F;p&gt;
&lt;p&gt;ヒーリングやクローンで対象を周囲になじませて消すモジュールです。モノクロは小さなゴミも意外と目立つので、気になるときだけ使い、なければ飛ばします。&lt;&#x2F;p&gt;


  &lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;h3 id=&quot;tone_equalizer&quot;&gt;tone equalizer&lt;&#x2F;h3&gt;
&lt;div class=&quot;module&quot;&gt;
  &lt;div class=&quot;module-image&quot;&gt;
    &lt;img
      src=&quot;https:&amp;#x2F;&amp;#x2F;codedchords.dev&amp;#x2F;blog&amp;#x2F;2026&amp;#x2F;06&amp;#x2F;darktable&amp;#x2F;tone-equalizer.webp?h=69da24bdfa31f0aacbdc&quot;
      alt=&quot;darktableのtone equalizerモジュール&quot; width=&quot;252&quot; height=&quot;422&quot;
      loading=&quot;lazy&quot;
    &#x2F;&gt;
  &lt;&#x2F;div&gt;
  &lt;div class=&quot;module-body&quot;&gt;

&lt;p&gt;特定の明るさ帯だけを覆い焼き・焼き込みしたいときに使います。たとえばシャドウだけ持ち上げたいが全体は明るくしたくない、といった局所的な明暗調整に向きます。&lt;&#x2F;p&gt;
&lt;p&gt;露出帯(-8EV〜0EV)ごとに明るさを持ち上げ・押し下げでき、全体ではなく狙った帯だけに局所コントラストを足せます。&lt;&#x2F;p&gt;


  &lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;h3 id=&quot;diffuse_or_sharpen&quot;&gt;diffuse or sharpen&lt;&#x2F;h3&gt;
&lt;div class=&quot;module&quot;&gt;
  &lt;div class=&quot;module-image&quot;&gt;
    &lt;img
      src=&quot;https:&amp;#x2F;&amp;#x2F;codedchords.dev&amp;#x2F;blog&amp;#x2F;2026&amp;#x2F;06&amp;#x2F;darktable&amp;#x2F;diffuse-or-sharpen.webp?h=022587df922850e88baf&quot;
      alt=&quot;darktableのdiffuse or sharpenモジュール&quot; width=&quot;249&quot; height=&quot;689&quot;
      loading=&quot;lazy&quot;
    &#x2F;&gt;
  &lt;&#x2F;div&gt;
  &lt;div class=&quot;module-body&quot;&gt;

&lt;p&gt;仕上げに解像感を一段上げたいときに使うシャープ化モジュールです。&lt;&#x2F;p&gt;
&lt;p&gt;偏微分方程式ベースで、プリセット(sharpen demosaicingなど)から選ぶと扱いやすくなります。軽く整える程度なら、旧来の &lt;code&gt;sharpen&lt;&#x2F;code&gt; モジュールでも十分です。&lt;&#x2F;p&gt;


  &lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;h3 id=&quot;crop&quot;&gt;crop&lt;&#x2F;h3&gt;
&lt;div class=&quot;module&quot;&gt;
  &lt;div class=&quot;module-image&quot;&gt;
    &lt;img
      src=&quot;https:&amp;#x2F;&amp;#x2F;codedchords.dev&amp;#x2F;blog&amp;#x2F;2026&amp;#x2F;06&amp;#x2F;darktable&amp;#x2F;crop.webp?h=04787ffd1a5ab4fab02f&quot;
      alt=&quot;darktableのcropモジュール&quot; width=&quot;252&quot; height=&quot;258&quot;
      loading=&quot;lazy&quot;
    &#x2F;&gt;
  &lt;&#x2F;div&gt;
  &lt;div class=&quot;module-body&quot;&gt;

&lt;p&gt;周辺の不要な部分を切り落として構図を整えたいときに使います。&lt;&#x2F;p&gt;
&lt;p&gt;darktableは露出やトーンの調整を画面全体に対して効かせるので、トリミングは仕上げの段階に回します。アスペクト比は自由(freehand)のまま、不要な周辺を切り落として構図を決めます。&lt;&#x2F;p&gt;


  &lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;h2 id=&quot;References&quot;&gt;References&lt;&#x2F;h2&gt;
&lt;div class=&quot;references&quot;&gt;
    &lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;docs.darktable.org&#x2F;usermanual&#x2F;development&#x2F;en&#x2F;&quot;&gt;darktable user manual&lt;&#x2F;a&gt;. darktable公式ユーザーマニュアル&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;docs.darktable.org&#x2F;usermanual&#x2F;development&#x2F;en&#x2F;overview&#x2F;workflow&#x2F;process&#x2F;&quot;&gt;darktable user manual&lt;&#x2F;a&gt;.「the pixelpipe and module order」scene-referredワークフローと処理の流れ&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;docs.darktable.org&#x2F;usermanual&#x2F;development&#x2F;en&#x2F;module-reference&#x2F;processing-modules&#x2F;lens-correction&#x2F;&quot;&gt;darktable user manual&lt;&#x2F;a&gt;.「lens correction」モジュール&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;docs.darktable.org&#x2F;usermanual&#x2F;development&#x2F;en&#x2F;module-reference&#x2F;processing-modules&#x2F;rotate-perspective&#x2F;&quot;&gt;darktable user manual&lt;&#x2F;a&gt;.「rotate and perspective」モジュール&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;docs.darktable.org&#x2F;usermanual&#x2F;development&#x2F;en&#x2F;module-reference&#x2F;processing-modules&#x2F;crop&#x2F;&quot;&gt;darktable user manual&lt;&#x2F;a&gt;.「crop」モジュール&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;docs.darktable.org&#x2F;usermanual&#x2F;development&#x2F;en&#x2F;module-reference&#x2F;processing-modules&#x2F;sigmoid&#x2F;&quot;&gt;darktable user manual&lt;&#x2F;a&gt;.「sigmoid」モジュール&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;lensfun.github.io&#x2F;&quot;&gt;Lensfun&lt;&#x2F;a&gt;. レンズ補正データベースのプロジェクトサイト(&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;lensfun&#x2F;lensfun&quot;&gt;GitHub リポジトリ&lt;&#x2F;a&gt;)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;discuss.pixls.us&#x2F;t&#x2F;darktable-4-8-location-of-lensfun-database-for-personal-use&#x2F;44682&quot;&gt;discuss.pixls.us&lt;&#x2F;a&gt;.「darktable 4.8 location of lensfun database for personal use」ユーザー領域へのLensfunデータ追加方法&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;

&lt;&#x2F;div&gt;
</content>
        <summary type="html">RAW 現像に、無料でありながら高機能な darktable を選びました。RICOH GR IV Monochrome を手にしたのがきっかけです。とっつきにくいツールですが、その核心は scene-referred ワークフローにあります。本稿では、この考え方に沿ってモノクロ写真をどう現像していくのかを、実際の操作画面とともに、本当に使うモジュールだけに絞って解説します。
</summary>
        </entry><entry xml:lang="en">
        <title>Macバックアップ戦略・改訂版</title>
        <published>2026-06-09T13:37:30+09:00</published>
        <updated>2026-06-09T13:37:30+09:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2026/06/mac-backup/" type="text/html"/>
        <id>https://codedchords.dev/blog/2026/06/mac-backup/</id>
        
            <content type="html">&lt;img
  src=&quot;https:&amp;#x2F;&amp;#x2F;codedchords.dev&amp;#x2F;blog&amp;#x2F;2026&amp;#x2F;06&amp;#x2F;mac-backup&amp;#x2F;cover.webp?h=e1641700571b6a83b0d5&quot;
  alt=&quot;Cover&quot; width=&quot;1536&quot; height=&quot;864&quot; loading=&quot;lazy&quot;
&#x2F;&gt;&lt;details&gt;
&lt;summary&gt;Table of Contents&lt;&#x2F;summary&gt;
&lt;!-- toc --&gt;
&lt;&#x2F;details&gt;
&lt;span id=&quot;continue-reading&quot;&gt;&lt;&#x2F;span&gt;
&lt;p&gt;長らくMacのバックアップにはSuperDuperを使い、Bootableなクローンを作ってきました。その方針は、以前&lt;a href=&quot;https:&#x2F;&#x2F;codedchords.dev&#x2F;blog&#x2F;2025&#x2F;04&#x2F;backup-strategy-for-mac&#x2F;&quot;&gt;Apple Silicon時代のMacバックアップ最新戦略&lt;&#x2F;a&gt;で整理したとおりです。ですが新しいmacOSへの対応がなかなか進まず、Tahoeに至っては一年あまり経った今も正式版すら出ません。そこでSuperDuperを諦め、rsyncでホームディレクトリを鏡像コピーする方式に切り替えました。この記事はその続編であり、乗り換えの理由と設定方法をまとめたものです。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;なぜTime_Machineが嫌いか&quot;&gt;なぜTime Machineが嫌いか&lt;&#x2F;h2&gt;
&lt;p&gt;バックアップの話をすると、まずTime Machineを勧められます。ですが私は、ごく初期に使ったきり、その後はすっかり避けるようになりました。&lt;&#x2F;p&gt;
&lt;p&gt;もともとは、Bootableなクローンを作れるサードパーティツールを使っていたからです。
Bootableなクローンが作れれば、ディスクが壊れた際にはクローンからmacOSを起動して復旧できます。&lt;&#x2F;p&gt;
&lt;p&gt;ただし、現在ではBootableなクローンを技術的に作成できなくなりました(後述)。
それでも、Time Machineには不信感が根強く、直感が先に拒否します。その裏には技術的な理由が3つあります。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;不確実性&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Time Machineはバックアップ先を専用のアーカイブ(sparsebundle)として抱え込む。中で何が起きているかは見えず、壊れていても警告は出ない。実際、復元しようとしたらアーカイブが読めず、修復もできず、履歴を全部捨てて最初からやり直すしかなかったという報告は後を絶たない。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;破損に弱い&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;sparsebundleは中身を多数の小さなバンドファイルに分け、その内側に1つのファイルシステムを抱える構造になっている。個々のファイルを直接取り出すことはできず、必ずイメージ全体をマウントして読む。だからバンドや内部の目次(カタログ)が一部でも壊れると、イメージごとマウント不能になり、世代を問わず全データに手が届かなくなる。世代を積み上げる構造だけに、過去のバックアップまでまとめて道連れになりやすい。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;ブラックボックス&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;何がどうコピーされ、どう積み上げられているのか、仕組みそのものがユーザーからは見えない。バックアップ先を開いても何がどう入っているか分からず、「このファイルが今そこにある」とFinderで素朴に確かめることもできない。中で何が行われているか把握できないものに大事なデータを預けるのは、技術者としてどうにも信用しきれない。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;私が欲しいのはその逆です。バックアップ先を開けば、コピー元とそっくり同じ構造でファイルがそのまま並んでいて、いざというとき個別のファイルをドラッグで取り出せる。履歴はいりません。今この瞬間の鏡像が1つあれば十分です。見えて、触れて、そのまま取り出せること。Time Machineはこの要求に対して、仕組みからして向いていません。&lt;&#x2F;p&gt;
&lt;p&gt;そのため、私は丸ごとBootableなディスククローンを作成できるサードパーティ製のツールを利用してきました。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;macOSの変化で、bootableクローンが封じられた&quot;&gt;macOSの変化で、bootableクローンが封じられた&lt;&#x2F;h2&gt;
&lt;p&gt;ところが、ここ数年のmacOSの変化で、その前提が崩れました。サードパーティ製ツールによるBootableなクローンが、事実上できなくなったのです。経緯を追うと、じわじわと封じられてきたことが分かります。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Big Surでシステムとデータが分離&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;起動ディスクが、OSの入った読み取り専用のシステムボリュームと、ユーザーデータのデータボリュームに完全分離された。システム側は改ざん防止のため署名・封印され、サードパーティ製アプリが直接コピーできなくなった。OSを複製する役目はApple自身の仕組み(レプリケーター)に移り、それが動き続けるかどうかもApple次第になった。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Sequoia 15.2が決定打&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Appleがそのレプリケーターを壊し、SuperDuperはBootableなバックアップを作れなくなった。データ複製の終盤、PrebootやRecoveryをコピーするあたりで失敗する。これはツール側のバグではなく、Apple側の問題だと開発元が明言している。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Tahoeでは正式対応すら出せず&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;互換性の壁がさらに増え、SuperDuperは正式版を出せていない。Tahoe対応は暫定ベータ(v3.20系)でしのぐ状態が続いている。一時はベータでの改善に期待もしたが、一年あまり経ってもベータのまま。起動可能クローンへの望みは、もう捨てた。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;要点を取り違えないことが大事です。壊れたのはBootableなシステム丸ごとクローンであって、ホーム(データ)のコピーが禁じられたわけではありません。Appleが封じたのはシステムボリュームの複製で、ユーザーのデータをコピーすること自体は今も普通にできます。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;今日のmacOSでのバックアップ戦略&quot;&gt;今日のmacOSでのバックアップ戦略&lt;&#x2F;h2&gt;
&lt;p&gt;ここで要件が変わります。&lt;&#x2F;p&gt;
&lt;p&gt;Bootableにできないのなら、システムボリュームまで丸ごとコピーする意味はもうありません。bootableという目的が消えた以上、「全部コピーする」根拠も一緒に消えました。残ったのは、自分のデータだけを守れればいい、という縮退した要求です。&lt;&#x2F;p&gt;
&lt;p&gt;つまり「ホームディレクトリだけでいい」は、最初からそう思っていたわけではありません。bootableを失った結果として、そこまで切り詰めた制約の上に成り立っています。この経緯を踏まえると、要件は次のように整理できます。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;バックアップ対象はホームディレクトリのみ。システムは諦める。&lt;&#x2F;li&gt;
&lt;li&gt;アプリが&lt;code&gt;~&#x2F;Library&lt;&#x2F;code&gt;配下などに書く、ユーザーが関知しないデータも要らない。多くは再生成されるので、守る価値がない。&lt;&#x2F;li&gt;
&lt;li&gt;差分でいい。変わっていないファイルは書き換えず、変わったぶんだけ転送する。&lt;&#x2F;li&gt;
&lt;li&gt;世代管理はいらない。常にコピー元と同じ、今この瞬間の鏡像が1つあればいい。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;rsyncのメリット&quot;&gt;rsyncのメリット&lt;&#x2F;h2&gt;
&lt;p&gt;この縮退した要件に、rsyncはきれいに合います。&lt;&#x2F;p&gt;
&lt;p&gt;第一に、差分転送が本職です。rsyncは初期状態で、サイズと更新日時を見て一致するファイルをまるごとスキップします。変わっていないファイルは触らず、変わったぶんだけ送ります。「変更ないファイルは書き換えたくない」という要求が、特別な設定なしにそのまま満たされます。&lt;&#x2F;p&gt;
&lt;p&gt;第二に、コピー先がただのファイルになります。バックアップ先は元と同じフォルダ階層がそのまま並ぶので、Finderで全部見えますし、個別ファイルをドラッグで取り出せます。Time Machineの抽象化とは正反対の、見える鏡像が手に入ります。&lt;&#x2F;p&gt;
&lt;p&gt;第三に、世代を持たない運用ができます。&lt;code&gt;--delete&lt;&#x2F;code&gt;を付ければ、コピー元で消したものはバックアップ先からも消え、常に最新の一枚の鏡像が保たれます。履歴の束は作られません。&lt;&#x2F;p&gt;
&lt;p&gt;第四に、無料で、スクリプトに組めて、スケジュール実行まで自前で完結します。専用アプリのライセンスや、OSの更新に追従できないツールの都合で振り回されることもありません。&lt;&#x2F;p&gt;
&lt;!-- textlint-disable --&gt;
&lt;div class=&quot;admonition warning&quot;&gt;
    &lt;div class=&quot;admonition-icon admonition-icon-warning&quot;&gt;&lt;&#x2F;div&gt;
    &lt;div class=&quot;admonition-content&quot;&gt;
        &lt;strong class=&quot;admonition-title&quot;&gt;標準のrsyncは使わない&lt;&#x2F;strong&gt;
        &lt;p&gt;Sequoia&#x2F;Tahoe標準のrsyncは&lt;code&gt;openrsync&lt;&#x2F;code&gt;という別実装で、出来がよくありません。&lt;code&gt;-a&lt;&#x2F;code&gt;で特殊ファイルに当たると止まる、拡張属性でクラッシュするといった報告があります。標準のものは避け、Homebrewで本家のrsync(3.x系)を入れて使いましょう。&lt;&#x2F;p&gt;

    &lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;!-- textlint-enable --&gt;
&lt;h2 id=&quot;準備&quot;&gt;準備&lt;&#x2F;h2&gt;
&lt;p&gt;まずHomebrewで本家rsyncを入れます。TahoeはApple Silicon専用なので、入れると&lt;code&gt;&#x2F;opt&#x2F;homebrew&#x2F;bin&#x2F;rsync&lt;&#x2F;code&gt;に置かれます。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;brew install rsync&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;もう1つ、フルディスクアクセスの設定が要ります。最近のmacOSでは、これが無いとホーム内の保護領域(メールなど)が読めず、警告も出さずに黙って飛ばされます。手で動作確認するときは使っているターミナルを、自動実行するときは後述のスクリプトを、システム設定のプライバシーとセキュリティ → フルディスクアクセスに追加しておきます。これを怠ると「バックアップしたつもりで一部入っていない」が起きます。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;コマンドと除外設計&quot;&gt;コマンドと除外設計&lt;&#x2F;h2&gt;
&lt;p&gt;バックアップ本体は、次の一本にまとめます。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot; data-name=&quot;~&#x2F;bin&#x2F;backup-home.sh&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-shebang z-shell z-meta z-shebang z-shell&quot;&gt;#!&#x2F;bin&#x2F;bash&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;DEST&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;&#x2F;Volumes&#x2F;Backup&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;LOG&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-normal z-shell&quot;&gt;$HOME&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt;&#x2F;Library&#x2F;Logs&#x2F;backup-home.log&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;if&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; !&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; &#x2F;sbin&#x2F;mount&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; |&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; grep&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt; -q &amp;quot;on &lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-normal z-shell&quot;&gt;$DEST&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; then&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-function z-builtin&quot;&gt;  echo&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;$(&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;date&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-normal z-shell&quot;&gt; $DEST&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt; not mounted, skipped&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; &amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-normal z-shell&quot;&gt;$LOG&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-function z-builtin&quot;&gt;  exit&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;fi&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;&#x2F;opt&#x2F;homebrew&#x2F;bin&#x2F;rsync&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; -aE --delete --info=progress2&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt;  --exclude=&amp;#39;&#x2F;Library&#x2F;&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt;  --exclude=&amp;#39;.Trash&#x2F;&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt;  --exclude=&amp;quot;.cache&#x2F;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt;  --exclude=&amp;#39;tmp&#x2F;&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt;  --exclude=&amp;#39;.DS_Store&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt;  --exclude=&amp;#39;&#x2F;pCloud Drive&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt;  --exclude=&amp;#39;&#x2F;.pcloud&#x2F;&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;  &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-normal z-shell&quot;&gt;$HOME&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt;&#x2F;&amp;quot; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-normal z-shell&quot;&gt;$DEST&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt;&#x2F;home&#x2F;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; &amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-normal z-shell&quot;&gt;$LOG&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; 2&amp;gt;&amp;amp;1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-function z-builtin&quot;&gt;echo&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;$(&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;date&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt; done&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; &amp;gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-normal z-shell&quot;&gt;$LOG&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;先頭の&lt;code&gt;if ! &#x2F;sbin&#x2F;mount ...&lt;&#x2F;code&gt;は、バックアップ先が未マウントのときに内蔵ディスクへ誤って書き込む事故を防ぐガードです。&lt;code&gt;-a&lt;&#x2F;code&gt;は権限・更新日時・シンボリックリンクなどを保ったまま再帰コピーし、&lt;code&gt;-E&lt;&#x2F;code&gt;はmacOSの拡張属性を保持します。&lt;code&gt;--delete&lt;&#x2F;code&gt;でコピー元から消したものをバックアップ先からも消し、常に鏡像に保ちます。&lt;code&gt;--info=progress2&lt;&#x2F;code&gt;は全体の総進捗を一行で表示します。&lt;code&gt;$HOME&#x2F;&lt;&#x2F;code&gt;の末尾スラッシュは「ホームの中身を」コピーする指定で、これが無いとhome自体が一段深く入れ子になります。&lt;&#x2F;p&gt;
&lt;p&gt;除外設計が実は一番の勘どころになります。詰まりの原因はほぼここに集約されます。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;.Trash&lt;&#x2F;code&gt;はゴミ箱、&lt;code&gt;.cache&lt;&#x2F;code&gt;や&lt;code&gt;tmp&lt;&#x2F;code&gt;は再生成される一時データ、&lt;code&gt;.DS_Store&lt;&#x2F;code&gt;はFinderの表示情報。どれもバックアップする価値がない。&lt;&#x2F;li&gt;
&lt;li&gt;クラウドや外部接続の仮想ドライブも必ず外す。ローカルに実体がなく、rsyncが舐めるとオンデマンドのダウンロードを次々誘発し、激遅やタイムアウト、最悪はクラウド上の全データの引きずり下ろしを招く。iCloud DriveやDropbox、OneDrive、Google Driveは&lt;code&gt;Library&#x2F;CloudStorage&lt;&#x2F;code&gt;や&lt;code&gt;Library&#x2F;Mobile Documents&lt;&#x2F;code&gt;にあるので、&lt;code&gt;&#x2F;Library&#x2F;&lt;&#x2F;code&gt;を外せば一緒に消える。&lt;code&gt;pCloud Drive&lt;&#x2F;code&gt;のようにホーム直下へマウントされるものだけ、個別に除外する。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;&lt;code&gt;Library&lt;&#x2F;code&gt;配下をどこまで残すかは判断が要ります。大半はアプリが再生成する状態ファイルなので、丸ごと&lt;code&gt;--exclude=&#x27;Library&#x2F;&#x27;&lt;&#x2F;code&gt;で外しても困らない人は多いでしょう。ただしローカルにしか実体のないデータ(ローカル保存のメールなど)がある場合は、その特定フォルダだけ残す配慮がいります。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;自動化&quot;&gt;自動化&lt;&#x2F;h2&gt;
&lt;p&gt;週1回の自動実行は、非推奨のcronではなくlaunchdで組みます。さきほどの&lt;code&gt;~&#x2F;bin&#x2F;backup-home.sh&lt;&#x2F;code&gt;に実行権を付けます。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;chmod +x ~&#x2F;bin&#x2F;backup-home.sh&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;次に&lt;code&gt;~&#x2F;Library&#x2F;LaunchAgents&#x2F;com.user.backup-home.plist&lt;&#x2F;code&gt;を作ります。毎週日曜の午前3時に走る例です(Weekdayの0が日曜)。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;xml&quot; data-name=&quot;~&#x2F;Library&#x2F;LaunchAgents&#x2F;com.user.backup-home.plist&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;lt;?&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;xml&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-other z-attribute-name&quot;&gt; version&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;1.0&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-other z-attribute-name&quot;&gt; encoding&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;UTF-8&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;?&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-tag z-keyword z-other z-doctype&quot;&gt;&amp;lt;!DOCTYPE&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt; plist PUBLIC &amp;quot;-&#x2F;&#x2F;Apple&#x2F;&#x2F;DTD PLIST 1.0&#x2F;&#x2F;EN&amp;quot; &amp;quot;http:&#x2F;&#x2F;www.apple.com&#x2F;DTDs&#x2F;PropertyList-1.0.dtd&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;plist&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-other z-attribute-name&quot;&gt; version&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;1.0&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;dict&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;  &amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;key&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt;Label&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;key&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;  &amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;string&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt;com.user.backup-home&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;string&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;  &amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;key&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt;ProgramArguments&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;key&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;  &amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;array&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;    &amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;string&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt;&#x2F;Users&#x2F;ユーザ名&#x2F;bin&#x2F;backup-home.sh&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;string&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;  &amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;array&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;  &amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;key&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt;StartCalendarInterval&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;key&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;  &amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;dict&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;    &amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;key&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt;Weekday&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;key&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;integer&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt;0&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;integer&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;    &amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;key&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt;Hour&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;key&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;integer&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt;3&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;integer&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;    &amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;key&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt;Minute&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;key&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;integer&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt;0&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;integer&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;  &amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;dict&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;dict&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;plist&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;登録します。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;launchctl bootstrap gui&#x2F;$(id -u) ~&#x2F;Library&#x2F;LaunchAgents&#x2F;com.user.backup-home.plist&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;launchdの利点は、指定時刻にMacが起動していなくても、次に起動したときに取りこぼしを拾って実行してくれる点です。cronのように「その時刻に寝ていたら丸ごと飛ぶ」ということがありません。複数回ぶんが溜まっても、起動時に走るのは1回にまとめられます。週一の用途なら、これで実用上困りません。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;つまずきどころ&quot;&gt;つまずきどころ&lt;&#x2F;h2&gt;
&lt;p&gt;実際に動かすと、たいてい最初の数回はここで引っかかります。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;初回はホーム全体のフルコピーなので、容量とドライブ速度によっては数時間かかる。差分で速くなるのは2回目以降。止まっているのか遅いだけなのかは、&lt;code&gt;du -sk &#x2F;Volumes&#x2F;Backup&#x2F;home&lt;&#x2F;code&gt;を時間を空けて2回打ち、数字が増えているかで判別する。&lt;&#x2F;li&gt;
&lt;li&gt;異常に遅い・止まる場合は、まず標準の&lt;code&gt;&#x2F;usr&#x2F;bin&#x2F;rsync&lt;&#x2F;code&gt;(openrsync)を叩いていないか&lt;code&gt;which rsync&lt;&#x2F;code&gt;で確認する。そして上のクラウド系の除外が効いているかを見る。GoProなどをMTP接続してマウントしている場合、それも&lt;code&gt;Library&#x2F;CloudStorage&lt;&#x2F;code&gt;に入り込んでタイムアウトの山を作るので、除外で一掃される。&lt;&#x2F;li&gt;
&lt;li&gt;Permission Deniedが出ても、rsyncはそのファイルを飛ばして続行する。多くはフルディスクアクセス不足か、root所有の触れないファイルだ。前者は設定で解決し、後者は無視してよいが、拒否されたのが自分の大事なデータでないかだけは確認する。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;まとめ&quot;&gt;まとめ&lt;&#x2F;h2&gt;
&lt;p&gt;この構成にも、諦めた点はあります。起動可能なクローンではないので、ディスクが飛んだら、まずmacOSを入れ直し、それからホームを書き戻す手間が残ります。アプリの再インストールも要ります。「つなげば即座に元通り」とはいきません。そこは割り切りです。&lt;&#x2F;p&gt;
&lt;p&gt;それでも私は、こちらを選びました。中身が見えて、いざとなれば一ファイルから引き出せて、仕組みを丸ごと自分の手で握れる。バックアップに一番ほしいのは、派手な復旧速度ではなく、この「見えている」という安心でした。OSやアプリの都合に振り回されないかぎり、この鏡像は週末ごとに静かに更新され続けてくれます。それだけで、私には十分です。&lt;&#x2F;p&gt;
</content>
        <summary type="html">長年使ってきた起動可能クローンが、macOSの変化でついに作れなくなりました。SuperDuperを手放し、信用しきれないTime Machineにも戻りたくない。残された道はどこにあるのか。見えて、触れて、そのまま取り出せるバックアップを求めて、rsyncによる鏡像コピーへたどり着くまでの記録です。
</summary>
        </entry><entry xml:lang="en">
        <title>三菱UFJ銀行のPPAP廃止は、半歩前進で半歩後退</title>
        <published>2026-06-08T00:00:00+00:00</published>
        <updated>2026-06-08T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2026/06/mufg-ppap/" type="text/html"/>
        <id>https://codedchords.dev/blog/2026/06/mufg-ppap/</id>
        
            <content type="html">&lt;!-- textlint-disable --&gt;
&lt;img
  src=&quot;https:&amp;#x2F;&amp;#x2F;codedchords.dev&amp;#x2F;blog&amp;#x2F;2026&amp;#x2F;06&amp;#x2F;mufg-ppap&amp;#x2F;cover.webp?h=027a043bdcc9bd7b745e&quot;
  alt=&quot;Cover&quot; width=&quot;1536&quot; height=&quot;864&quot; loading=&quot;lazy&quot;
&#x2F;&gt;&lt;!-- textlint-enable --&gt;
&lt;p&gt;三菱UFJ銀行が2026年6月8日付で「&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.bk.mufg.jp&#x2F;info&#x2F;pdf&#x2F;20260608_send_attachments.pdf&quot;&gt;当行からの添付ファイル送信方法の変更に関するご案内&lt;&#x2F;a&gt;」を公表しました。
日本を代表するメガバンクがまだPPAPやっていたと衝撃を受けました。
内容を読んで考えさせられたので記録しておきます。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;三菱UFJ銀行のアナウンス&quot;&gt;三菱UFJ銀行のアナウンス&lt;&#x2F;h2&gt;
&lt;p&gt;要点はシンプルです。&lt;&#x2F;p&gt;
&lt;p&gt;同行は、お客さま側のセキュリティを確保するため、パスワード付き添付ファイルのメール送信を原則取り止めると発表しました。
2026年7月18日より順次、添付ファイルを送る際は専用のダウンロードサイトを利用する方式へ変更されます。&lt;&#x2F;p&gt;
&lt;p&gt;理由として挙げられているのは次の2点です。
これまでの「メールでパスワード付きZIPファイルを送り、パスワードを別送する方法」、いわゆる &lt;strong&gt;PPAP&lt;&#x2F;strong&gt; は、ファイルが暗号化されているためメール受信時のマルウェアチェックが困難であること。
そして近年、パスワード付きZIPファイルを悪用したサイバー攻撃の事例が確認されていることです。&lt;&#x2F;p&gt;
&lt;p&gt;新方式では、同行の役職員が添付ファイルを送る際、メール本文に専用ダウンロードサイトへアクセスするためのURLを記載します。
受け手はそのサイトにアクセスし、別送されるダウンロード専用のパスワードを使ってファイルを取得します。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;PPAPの何が問題だったのか&quot;&gt;PPAPの何が問題だったのか&lt;&#x2F;h2&gt;
&lt;p&gt;PPAPの是非については、昨年「&lt;a href=&quot;&#x2F;blog&#x2F;2025&#x2F;06&#x2F;aws-sns&#x2F;&quot;&gt;AWSからSMSにメッセージを送る&lt;&#x2F;a&gt;」という記事で一度整理しました。&lt;&#x2F;p&gt;
&lt;p&gt;そのとき、機密文書をメールで送る手段を秘匿性と本人確認性の観点で並べて評価したのですが、結論は変わっていません。&lt;&#x2F;p&gt;
&lt;p&gt;PPAP、つまり暗号化ファイルとパスワードを同じ経路で送る方法は、1通盗まれればすべて漏洩します。
パスワードを別メールにしても、同じメールインフラを流れる以上、傍受や誤送信のリスクは本質的には下がりません。
加えて、暗号化されたZIPはメールゲートウェイでウイルススキャンできないため、マルウェアの運び屋になりやすい。
三菱UFJ銀行が今回理由として挙げているのは、まさにこの最後の点です。&lt;&#x2F;p&gt;
&lt;p&gt;ですから、PPAPをやめるという判断そのものは正しいと思います。
日本でも2020年に政府がPPAPの廃止方針を打ち出して以降の流れに沿っていますし、銀行という立場で旗を振る意味も小さくありません。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;新方式は本当に安全になったのか&quot;&gt;新方式は本当に安全になったのか&lt;&#x2F;h2&gt;
&lt;p&gt;問題は、その置き換え先です。&lt;&#x2F;p&gt;
&lt;p&gt;新方式は「メール本文にダウンロードサイトのURLを記載し、パスワードは別送する」というものでした。
マルウェアスキャンの観点では確かに前進しています。
ファイルが暗号化ZIPとしてメールに乗らなくなるので、受信側のゲートウェイで中身を検査できるようになるからです。&lt;&#x2F;p&gt;
&lt;p&gt;しかし、フィッシング耐性という観点では、むしろ後退しかねません。&lt;&#x2F;p&gt;
&lt;p&gt;ひとつは、銀行が自ら「メール本文のURLをクリックさせる」習慣を送信先に植え付けてしまう点です。
銀行はこれまでフィッシング対策として、「当行からのメールにURLは記載しません」「メール内のリンクは開かないでください」と顧客には教育してきたはずです。
メールの送信先は顧客ではないと思いますが、今回はその逆を習慣づけることになります。
なりすましメールに偽のダウンロードURLが貼られていても、利用者は見分けがつかなくなります。&lt;&#x2F;p&gt;
&lt;p&gt;もうひとつは、「パスワードを別送する」という発想がPPAPのままという点です。
日ごろ支援しているコンサルテーション会社やITベンダーはちゃんと技術的に支援できなかったんでしょうか？&lt;&#x2F;p&gt;
&lt;p&gt;URLとパスワードを両方メールで送るのであれば、構造的にはPPAPの暗号化ZIPをWebサイトに置き換えただけです。
同じ経路を流れる以上、傍受や誤送信による漏洩リスクは解決していません。
マルウェアの問題は片付いても、秘匿性の問題は手つかずなのです。&lt;&#x2F;p&gt;
&lt;p&gt;整理すると、今回の変更は「マルウェアスキャン」という一点ではマシになる一方で、フィッシング耐性では弱点を抱え込む、惜しい設計だと感じます。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;本来あるべき姿&quot;&gt;本来あるべき姿&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;a href=&quot;&#x2F;blog&#x2F;2025&#x2F;06&#x2F;aws-sns&quot;&gt;以前の記事&lt;&#x2F;a&gt;でも書きましたが、
現実的なのは認証付きのクラウドストレージで共有する方法でした。
受け手がログインして初めてファイルにアクセスできる仕組みなら、URLが単体で漏れても無効ですし、誰がいつアクセスしたかのログも残せます。
パスワードを別送する必要すらありません。&lt;&#x2F;p&gt;
&lt;p&gt;メールの送付先は取引業者だと思いますから、銀行が共通の認証を払い出すのは困難です。
たとえばBoxやDropboxのようなクラウドストレージであれば、受け手は無料のアカウントを気軽に作れます。
銀行側が取引先ごとにアカウントを発行・運用しなくても、受け手がログインして初めてファイルにアクセスできる仕組みを成り立たせられるわけです。
URLが単体で漏れても無効ですし、誰がいつアクセスしたかのログも残ります。&lt;&#x2F;p&gt;
&lt;p&gt;さらに言えば、この方式ならメールにリンクを書く必要すらありません。
ファイルを共有すれば、受け手にはクラウドストレージ側から「共有されました」という通知が届きます。
受け手は自分が信頼しているサービスにログインしてファイルを取りに行くだけです。
冒頭で挙げた、メール内URLをクリックさせる習慣づけという問題が、根本から消えてなくなるのです。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;より根本的な解はないのか&quot;&gt;より根本的な解はないのか&lt;&#x2F;h2&gt;
&lt;p&gt;もっとも、銀行ともあろうものがファイルの受け渡しを外部のクラウドサービスに丸ごと預けるのも、それはそれで引っかかります。
委託先管理やデータの所在、サービスへの従属といった問題が新たに生じるからです。
だとすれば、現実的な落としどころは、銀行が認証付きの受け渡しポータルを自前で持つことでしょう。
インターネットバンキングという認証基盤と運用ノウハウをすでに備え、取引先の本人確認も日常的に行っている組織です。
Boxがやっていることを内製すればよいだけです。技術力と体力の両面で、銀行はそれができる立場にあります。&lt;&#x2F;p&gt;
&lt;p&gt;では、もっと教科書的な根本解はないのか。
あります。受け手の証明書でメールそのものを暗号化・署名するS&#x2F;MIME、いわゆるPKIです。
外部サービスやポータル、パスワードの別送といった仕組みが一切要らず、本人性と秘匿性をエンドツーエンドで担保できる、理屈のうえでは最も美しい解です。&lt;&#x2F;p&gt;
&lt;p&gt;ところがPKIは、米国ですら普及しませんでした。
証明書の発行や管理が高コストで手作業が多く、ユーザーごと・端末ごとに鍵を入れて回る運用負荷に耐えられなかったためです。
そして決定的なのは、&lt;strong&gt;送り手と受け手の双方が対応していないと成り立たない&lt;&#x2F;strong&gt;という両側依存です。
暗号化して送るには、相手があらかじめ証明書を用意していなければなりません。
相手が対応していなければ、文字どおり意味がない。
この鶏と卵の構造ゆえに、誰も最初の一歩を踏み出せませんでした。
受け手に「アカウントを作ってログインする」という自己完結した操作しか求めないポータル方式に世界が流れたのは、そのためです。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;それでもリーダーシップを期待したかった&quot;&gt;それでもリーダーシップを期待したかった&lt;&#x2F;h2&gt;
&lt;p&gt;ここで私が惜しいと思うのは、まさにこの一点です。
PKIが普及しなかった最大の理由が「最初の一歩を誰も踏み出せなかった」ことなら、その一歩を踏み出せる体力と影響力を持つ組織こそ、日本を代表するメガバンクのはずです。&lt;&#x2F;p&gt;
&lt;p&gt;率先してS&#x2F;MIMEを導入し、添付ファイルをやり取りするような主要な取引先には導入を促す。
場合によっては証明書発行の基盤を貸し出したり、運用を支援したりする。
そうやって両側依存の壁を、影響力のある側から崩していく。
そんなリーダーシップを見せてくれたら、日本全体のメール文化が一段前に進んだかもしれません。&lt;&#x2F;p&gt;
&lt;p&gt;現実的な着地は認証付きポータルでよいと思います。
ただ、PPAPをやめるという入口が正しかっただけに、出口がもう一歩踏み込めなかったのは惜しい。
日本をリードする銀行のやることだからこそ、ここにこそリーダーシップを期待したかった、というのが私の正直な感想です。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;References&quot;&gt;References&lt;&#x2F;h2&gt;
&lt;!-- textlint-disable --&gt;
&lt;div class=&quot;references&quot;&gt;
    &lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.bk.mufg.jp&#x2F;info&#x2F;pdf&#x2F;20260608_send_attachments.pdf&quot;&gt;株式会社三菱UFJ銀行&lt;&#x2F;a&gt;. 「当行からの添付ファイル送信方法の変更に関するご案内」（2026年6月8日）&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;&#x2F;blog&#x2F;2025&#x2F;06&#x2F;aws-sns&#x2F;&quot;&gt;Coded Chords&lt;&#x2F;a&gt;. 「AWSからSMSにメッセージを送る」（2025年6月9日）&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;

&lt;&#x2F;div&gt;
&lt;!-- textlint-enable --&gt;
</content>
        <summary type="html">日本を代表する銀行がPPAPの廃止を発表しました。マルウェア対策としては正しい一歩ですが、新しい受け渡し方法には見過ごせない落とし穴が残っています。</summary>
        </entry><entry xml:lang="en">
        <title>Amazon S3からCloudflare R2への移行</title>
        <published>2026-05-22T00:00:00+00:00</published>
        <updated>2026-05-22T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2026/05/cloudflare-r2/" type="text/html"/>
        <id>https://codedchords.dev/blog/2026/05/cloudflare-r2/</id>
        
            <content type="html">&lt;!-- textlint-disable --&gt;
&lt;img
  src=&quot;https:&amp;#x2F;&amp;#x2F;codedchords.dev&amp;#x2F;blog&amp;#x2F;2026&amp;#x2F;05&amp;#x2F;cloudflare-r2&amp;#x2F;cover.webp?h=1e92776e8f350ad0d4c1&quot;
  alt=&quot;Cover&quot; width=&quot;1536&quot; height=&quot;864&quot; loading=&quot;lazy&quot;
&#x2F;&gt;&lt;!-- textlint-enable --&gt;
&lt;p&gt;以前「&lt;a href=&quot;https:&#x2F;&#x2F;codedchords.dev&#x2F;blog&#x2F;2026&#x2F;01&#x2F;blog-to-zola-aws-cleanup&#x2F;&quot;&gt;ブログをZolaに移行、AWSの後始末&lt;&#x2F;a&gt;」で、Next.js + Amplify構成のブログをZolaへ移し、Amplifyを含む大半のAWSリソースを削除しました。ただ、そのとき1つだけ削除せずに残したものがあります。有償のWEBフォントを配信するためのS3バケットとCloudFrontです。&lt;&#x2F;p&gt;
&lt;p&gt;本記事では、この最後のAWSリソースをCloudflare R2へ移した記録をまとめます。題材はフォント1つですが、個人ブログのスタティックなリソースをS3とR2のどちらに置くか、という選択の話でもあります。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;移行前の構成&quot;&gt;移行前の構成&lt;&#x2F;h2&gt;
&lt;p&gt;配信していたのは有償のWEBフォントです。このフォントはライセンス上、誰でもwoff2ファイルをダウンロードできる状態にしておくわけにはいきません。一方でWEBフォントである以上、ブラウザからは取得できる必要があります。この相反する要件を、移行前はAWS側で次のように満たしていました&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-oac-1&quot;&gt;&lt;a href=&quot;#fn-oac&quot;&gt;1&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;woff2ファイルをS3バケットに保管し、その前段のCloudFrontから配信&lt;&#x2F;li&gt;
&lt;li&gt;CloudFront FunctionでリクエストのRefererヘッダを検査し、ブログのドメイン以外からのアクセスを遮断&lt;&#x2F;li&gt;
&lt;li&gt;S3バケットポリシーにも同じReferer条件を設定し、CloudFrontを経由しないS3への直接アクセスも遮断&lt;&#x2F;li&gt;
&lt;li&gt;フォントがCloudFrontのドメイン(ブログとは別オリジン)から読み込まれるため、S3側のCORS設定でブログのドメインからの要求のみを許可&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;ブログのCSSでは、すべての &lt;code&gt;@font-face&lt;&#x2F;code&gt; がこのCloudFrontのURLを参照していました。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;Cloudflare_R2_への移行&quot;&gt;Cloudflare R2 への移行&lt;&#x2F;h2&gt;
&lt;p&gt;ブログのワークロードは、すでにCloudflareに移っていました。ホスティングはCloudflare Workersの静的アセット配信で動いており、フォントだけをAWSに残しておく理由は薄くなっていました。配信元をS3 + CloudFrontからCloudflare R2に移すと、次のメリットがあります。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;AWSとCloudflareに分かれていたインフラの一本化&lt;&#x2F;li&gt;
&lt;li&gt;Referer制限のための仕組み(CloudFront Function・バケットポリシーの条件・CORS)の全廃&lt;&#x2F;li&gt;
&lt;li&gt;フォントの同一オリジン配信化(別オリジンへの &lt;code&gt;preconnect&lt;&#x2F;code&gt; やCSP調整が不要)&lt;&#x2F;li&gt;
&lt;li&gt;R2のストレージ無料枠(10GB)に収まる配信コスト&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;特に大きいのは2番目です。R2バケットは、公開設定を有効にしない限り外部から到達できるURLを持たず、フォントへのアクセス手段はWorkerからのR2 Bindingだけになります。S3 + CloudFrontでは、公開バケットへのアクセスをReferer条件で絞り込む必要がありました。R2では公開URLがそもそも存在しないため、アクセス元を判定する仕組み自体が要らなくなります。守るための要素が減ることは、設定ミスの余地が減ることでもあります。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;移行後の保護モデル&quot;&gt;移行後の保護モデル&lt;&#x2F;h2&gt;
&lt;p&gt;新しい構成では、フォントの保護を4つのレイヤーで担保しています。&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;#&lt;&#x2F;th&gt;&lt;th&gt;レイヤー&lt;&#x2F;th&gt;&lt;th&gt;設定の実体&lt;&#x2F;th&gt;&lt;th&gt;防ぐ脅威&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;1&lt;&#x2F;td&gt;&lt;td&gt;バケット非公開&lt;&#x2F;td&gt;&lt;td&gt;r2.dev 無効・カスタムドメイン未割当・CORS なし&lt;&#x2F;td&gt;&lt;td&gt;バケット URL の直接スクレイプ、検索エンジンの索引&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;2&lt;&#x2F;td&gt;&lt;td&gt;R2 Binding 経由のみ&lt;&#x2F;td&gt;&lt;td&gt;&lt;code&gt;[[r2_buckets]]&lt;&#x2F;code&gt; 宣言により同一 Cloudflare アカウント内に限定&lt;&#x2F;td&gt;&lt;td&gt;他アカウントや外部ネットワークからの参照&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;3&lt;&#x2F;td&gt;&lt;td&gt;Worker が公開面を制限&lt;&#x2F;td&gt;&lt;td&gt;&lt;code&gt;&#x2F;fonts&#x2F;&amp;lt;file&amp;gt;&lt;&#x2F;code&gt; パスのみを公開し、不正なキーは弾く&lt;&#x2F;td&gt;&lt;td&gt;パストラバーサル、任意キーの READ、バケット列挙&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;4&lt;&#x2F;td&gt;&lt;td&gt;長寿命クレデンシャル不在&lt;&#x2F;td&gt;&lt;td&gt;R2 API トークンを発行しない&lt;&#x2F;td&gt;&lt;td&gt;コミットや CI ログ経由のトークン漏洩&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;設計の本質は、ライセンス違反が最も起きやすい経路、つまり公開バケットのURLがクローラに拾われて検索結果に載ることを消す点にあります。閲覧者がDevToolsからフォントを保存する行為や、第三者サイトからのホットリンクは別レイヤーの問題で、WEBフォント配信の仕組み上、完全には防げません。必要ならWorkerにReferer許可リストを足すこともできますが、今回は入れていません。私が利用しているフォントのライセンスでは、ライセンシーのドメインから配信することが求められていて、リクエスト元の検査までは要件になっていないためです。ただし、これはフォントごとに異なります。CORSやドメイン制限を技術的保護措置としてEULAで義務づけているフォントもあるので、利用するフォントのライセンスは必ず確認してください。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;Worker_と_R2_の構成&quot;&gt;Worker と R2 の構成&lt;&#x2F;h2&gt;
&lt;p&gt;実装は驚くほど小さく収まりました。まずR2バケットを作成します(ここでは &lt;code&gt;web-fonts&lt;&#x2F;code&gt; という名前にします)。公開設定は無効のままにし、S3と同じキー名でwoff2をアップロードします。あとはWorkerからbindingでつなぐだけです。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;code&gt;wrangler.toml&lt;&#x2F;code&gt; にR2バケットのbindingを宣言します。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;toml&quot; data-name=&quot;wrangler.toml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;name&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;blog&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;main&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;src&#x2F;index.js&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;compatibility_date&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;2026-02-17&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;assets&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;directory&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;.&#x2F;public&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;binding&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;ASSETS&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[[&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;r2_buckets&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;binding&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;FONTS&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;bucket_name&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;web-fonts&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Worker本体は、&lt;code&gt;&#x2F;fonts&#x2F;&lt;&#x2F;code&gt; で始まるリクエストをR2に取り次ぎ、それ以外は静的アセットに渡すだけです。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;javascript&quot; data-name=&quot;src&#x2F;index.js&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;const&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-constant z-js&quot;&gt; FONTS_PREFIX&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;&#x2F;fonts&#x2F;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;export default&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-modifier&quot;&gt;  async&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; fetch&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt;req&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt; env&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;    const&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-constant z-js&quot;&gt; url&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-new&quot;&gt; new&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; URL&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(req&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-property z-js z-source&quot;&gt;url)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;    if&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; (url&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;pathname&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;startsWith&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-variable z-other z-constant z-js&quot;&gt;(FONTS_PREFIX))&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;      const&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-constant z-js&quot;&gt; key&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; decodeURIComponent&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(url&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;pathname&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;slice&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-constant&quot;&gt;FONTS_PREFIX&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;length))&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;      &#x2F;&#x2F; Only flat keys in R2 (no subdir, no traversal). Anything else falls&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;      &#x2F;&#x2F; through to static assets — the theme also publishes under &#x2F;fonts&#x2F;.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;      if&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; (&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-js&quot;&gt;key&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; &amp;amp;&amp;amp; !&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;key&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;includes&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;..&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; &amp;amp;&amp;amp; !&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;key&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;includes&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;&#x2F;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;))&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;        const&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-constant z-js&quot;&gt; obj&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; await&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; env&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-constant&quot;&gt;FONTS&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;get&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-js&quot;&gt;key&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;        if&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; (&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-js&quot;&gt;obj&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;          const&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-constant z-js&quot;&gt; headers&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-new&quot;&gt; new&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; Headers&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;()&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;          obj&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;writeHttpMetadata&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-js&quot;&gt;headers&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;          headers&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;set&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;Content-Type&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;font&#x2F;woff2&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;          headers&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;set&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;Cache-Control&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;public, max-age=31536000, immutable&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;          headers&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;set&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;ETag&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; obj&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-property z-js z-source&quot;&gt;httpEtag)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;          return&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-new&quot;&gt; new&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; Response&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(obj&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-property z-js&quot;&gt;body&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;, {&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-js&quot;&gt; headers&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; }&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;        }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;      }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;    return&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; env&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-constant&quot;&gt;ASSETS&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;fetch&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-js&quot;&gt;req&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;  },&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;};&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;最後にCSSの参照先を書き換えます。&lt;code&gt;@font-face&lt;&#x2F;code&gt; の &lt;code&gt;src&lt;&#x2F;code&gt; は、これまでCloudFrontの絶対URLを指していましたが、同一オリジンの相対パス &lt;code&gt;&#x2F;fonts&#x2F;&lt;&#x2F;code&gt; に変わります。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;css&quot; data-name=&quot;custom.css&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-keyword z-keyword&quot;&gt;@font-face&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-type z-property-name z-css&quot;&gt;  font-family&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;WebFont&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-type z-property-name z-css&quot;&gt;  src&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function&quot;&gt; url&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;&#x2F;fonts&#x2F;WebFont-Regular.woff2&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-function z-misc&quot;&gt;    format&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;woff2&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-type z-property-name z-css&quot;&gt;  font-display&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; swap&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-type z-property-name z-css&quot;&gt;  font-weight&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 400&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-type z-property-name z-css&quot;&gt;  font-style&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; normal&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;CSS内のすべての &lt;code&gt;@font-face&lt;&#x2F;code&gt; で、CloudFrontの絶対URLを &lt;code&gt;&#x2F;fonts&#x2F;&lt;&#x2F;code&gt; で始まる相対パスに置き換えます。デプロイはmainへのpushでGitHub Actionsが &lt;code&gt;wrangler deploy&lt;&#x2F;code&gt; を実行する流れに乗せます。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;つまずいた点&quot;&gt;つまずいた点&lt;&#x2F;h2&gt;
&lt;p&gt;デプロイ用のAPIトークンの権限不足でつまずきました。GitHub Actionsが使う &lt;code&gt;CLOUDFLARE_API_TOKEN&lt;&#x2F;code&gt; は旧構成(静的アセット配信のみ)のときに発行したもので、Workers Scriptsの編集権限しかありませんでした。R2 bindingを含むWorkerを &lt;code&gt;wrangler deploy&lt;&#x2F;code&gt; すると、宣言したバケットの存在確認でR2のAPIを呼び出すため、初回のpushは &lt;code&gt;code: 10000 Authentication error&lt;&#x2F;code&gt; で失敗しました。&lt;&#x2F;p&gt;
&lt;p&gt;幸い、Cloudflare Workersのデプロイは原子的です。失敗時は旧Workerが稼働し続けるため、復旧作業中もサイトは旧CloudFront経由でフォントを配信し続け、見た目は保たれていました。&lt;&#x2F;p&gt;
&lt;p&gt;対応として、APIトークンにAccountスコープの &lt;code&gt;Workers R2 Storage: Edit&lt;&#x2F;code&gt; を追加しました。最終的に付与した権限セットは次のとおりです。&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;スコープ&lt;&#x2F;th&gt;&lt;th&gt;パーミッション&lt;&#x2F;th&gt;&lt;th&gt;用途&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;Account&lt;&#x2F;td&gt;&lt;td&gt;Workers Scripts: Edit&lt;&#x2F;td&gt;&lt;td&gt;Worker スクリプトのデプロイ&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Account&lt;&#x2F;td&gt;&lt;td&gt;Workers R2 Storage: Edit&lt;&#x2F;td&gt;&lt;td&gt;R2 binding 宣言時のバケット存在確認&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Account&lt;&#x2F;td&gt;&lt;td&gt;Account Settings: Read&lt;&#x2F;td&gt;&lt;td&gt;アカウント情報の照会&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Zone&lt;&#x2F;td&gt;&lt;td&gt;Workers Routes: Edit&lt;&#x2F;td&gt;&lt;td&gt;カスタムルートの設定&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;User&lt;&#x2F;td&gt;&lt;td&gt;Memberships: Read&lt;&#x2F;td&gt;&lt;td&gt;&lt;code&gt;&#x2F;memberships&lt;&#x2F;code&gt; API の呼び出し&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;User&lt;&#x2F;td&gt;&lt;td&gt;User Details: Read&lt;&#x2F;td&gt;&lt;td&gt;&lt;code&gt;wrangler whoami&lt;&#x2F;code&gt; 相当の照会&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;Cloudflare公式の「Edit Cloudflare Workers」テンプレートにはR2の権限が含まれていません。新しいbinding(R2 &#x2F; D1 &#x2F; KV &#x2F; Queuesなど)をWorkerに足すときは、デプロイ前にCIトークンの権限を見直すのが安全です。トークンを差し替えたあとは、失敗したジョブだけを再実行しました。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;DEPLOY_ID&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;$(&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;gh&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; run list --branch main&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt;  --workflow=&amp;quot;&amp;lt;デプロイ用ワークフロー名&amp;gt;&amp;quot; --limit&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 1&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt;  --json databaseId --jq &amp;#39;.[0].databaseId&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;gh&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt; run rerun &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-normal z-shell&quot;&gt;$DEPLOY_ID&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot; --failed&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;AWS_リソースの撤去&quot;&gt;AWS リソースの撤去&lt;&#x2F;h2&gt;
&lt;p&gt;R2配信が本番で安定したことを確認してから、AWS側を停止しました。撤去対象はCloudFrontディストリビューション、CloudFront Function、S3バケットの3つです。ディストリビューションIDは &lt;code&gt;aws cloudfront list-distributions&lt;&#x2F;code&gt;、バケット名は &lt;code&gt;aws s3 ls&lt;&#x2F;code&gt; で確認できます。以降のコマンドでは、それぞれの識別子を変数に入れてあるものとします。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;DIST_ID&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;&amp;lt;対象ディストリビューションのID&amp;gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;FUNCTION_NAME&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;&amp;lt;Referer を検査していた CloudFront Function 名&amp;gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;BUCKET&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;&amp;lt;フォントを置いていた S3 バケット名&amp;gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;CloudFrontディストリビューションは、いきなり削除できません。先に &lt;code&gt;Enabled = false&lt;&#x2F;code&gt; で無効化し、設定が全エッジに伝播するのを待ってから削除します。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;aws&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt; cloudfront get-distribution-config --id &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-normal z-shell&quot;&gt;$DIST_ID&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;  &amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &#x2F;tmp&#x2F;dist-config.json&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;jq&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt; -r &amp;#39;.ETag&amp;#39; &#x2F;tmp&#x2F;dist-config.json&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; &amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &#x2F;tmp&#x2F;dist-etag.txt&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;jq&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;#39;.DistributionConfig | .Enabled = false&amp;#39; &#x2F;tmp&#x2F;dist-config.json&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;  &amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &#x2F;tmp&#x2F;dist-config-disabled.json&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;aws&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt; cloudfront update-distribution --id &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-normal z-shell&quot;&gt;$DIST_ID&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt;  --if-match &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;$(&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;cat&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &#x2F;tmp&#x2F;dist-etag.txt&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt;  --distribution-config &amp;quot;file:&#x2F;&#x2F;&#x2F;tmp&#x2F;dist-config-disabled.json&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;code&gt;update-distribution&lt;&#x2F;code&gt; は &lt;code&gt;Status: InProgress&lt;&#x2F;code&gt; を返します。&lt;code&gt;Status: Deployed&lt;&#x2F;code&gt; に戻るまで伝播を待ちます(実測で約3分)。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;until&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;$(&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;aws&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt; cloudfront get-distribution --id &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-normal z-shell&quot;&gt;$DIST_ID&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt;  --query &amp;#39;Distribution.Status&amp;#39; --output text&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;Deployed&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; ];&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; do&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;  sleep&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 30&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;done&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;code&gt;Deployed&lt;&#x2F;code&gt; に戻ったら削除します。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;ETAG&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;$(&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;aws&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt; cloudfront get-distribution --id &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-normal z-shell&quot;&gt;$DIST_ID&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt;  --query &amp;#39;ETag&amp;#39; --output text&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;aws&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt; cloudfront delete-distribution --id &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-normal z-shell&quot;&gt;$DIST_ID&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot; --if-match &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-normal z-shell&quot;&gt;$ETAG&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;CloudFront Functionの削除では、&lt;code&gt;describe-function&lt;&#x2F;code&gt; で取得した現在のETagを &lt;code&gt;delete-function&lt;&#x2F;code&gt; に渡します。注意点として、FunctionはDEVELOPMENTとLIVEの2つのステージを持ち、両者を別々に更新しているとETagが食い違います。私の環境ではDEVELOPMENT側が新しく、&lt;code&gt;describe-function --stage DEVELOPMENT&lt;&#x2F;code&gt; で取ったETagでなければ &lt;code&gt;PreconditionFailed&lt;&#x2F;code&gt; になりました。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;ETAG&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;$(&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;aws&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt; cloudfront describe-function --name &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-normal z-shell&quot;&gt;$FUNCTION_NAME&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt;  --stage DEVELOPMENT --query &amp;#39;ETag&amp;#39; --output text&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;aws&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt; cloudfront delete-function --name &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-normal z-shell&quot;&gt;$FUNCTION_NAME&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot; --if-match &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-normal z-shell&quot;&gt;$ETAG&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;最後にS3バケットを空にして削除します。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;aws&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt; s3 rm &amp;quot;s3:&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-normal z-shell&quot;&gt;$BUCKET&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot; --recursive&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;aws&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt; s3api delete-bucket --bucket &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-normal z-shell&quot;&gt;$BUCKET&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;ACM証明書は、CloudFrontのデフォルトドメイン(&lt;code&gt;*.cloudfront.net&lt;&#x2F;code&gt;)のまま運用していて発行していなかったため、削除対象はありませんでした。これでフォント配信に関わるAWSリソースはすべて無くなり、配信はR2経由に一本化されました。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;移行して変わったこと&quot;&gt;移行して変わったこと&lt;&#x2F;h2&gt;
&lt;p&gt;移行の前後で、AWS側にあったCloudFrontディストリビューション、CloudFront Function、S3バケット、バケットポリシー、CORS設定がすべて消えました。残ったのはR2バケット1つと、ごく短いWorkerスクリプト1つです。&lt;&#x2F;p&gt;
&lt;p&gt;今回移したのはフォント一式というごく小さなリソースで、Cloudflareの無料枠の範囲で十分にまかなえています。コスト面より、管理対象のサービス数が減ったことのほうが効きます。フォント1種類のためにCloudFrontとS3とFunctionの3サービスを横断して設定を追っていた状態から、Cloudflareのダッシュボード内で完結する状態になりました。&lt;&#x2F;p&gt;
&lt;p&gt;今回はフォントが題材でしたが、結論はもっと一般的だと考えています。個人ブログのスタティックなリソースの置き場所としては、Amazon S3 + CloudFrontよりもCloudflare R2のほうが向いています。R2なら公開URLを持たせずにWorkerから読め、S3のように公開バケットを設定で囲い込む手間がいりません。ホスティングがCloudflareにあれば置き場も同じプラットフォームにまとまり、費用も無料枠と転送料無料で個人規模なら気になりません。&lt;&#x2F;p&gt;
&lt;p&gt;S3が劣るという話ではありません。ただ、個人ブログの規模で、すでにCloudflareを使っているなら、スタティックなリソースはR2に置くのが素直な選択だと思います。&lt;&#x2F;p&gt;
&lt;section class=&quot;footnotes&quot;&gt;
&lt;ol class=&quot;footnotes-list&quot;&gt;
&lt;li id=&quot;fn-oac&quot;&gt;
&lt;p&gt;より確実な構成にするなら、S3バケットを非公開にしてOAC(Origin Access Control)経由でのみ読ませる方法もありました。ただしWEBフォントはページの一部としてブラウザに読み込まれる以上、閲覧者によるダウンロードまで完全に防ぐことはどのみちできません。完全な防御は不可能だという前提で、ある程度は妥協した構成でした。 &lt;a href=&quot;#fr-oac-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;&#x2F;section&gt;
</content>
        <summary type="html">ブログに最後まで残っていたAWSリソースは、有償WEBフォントの
配信でした。これをAmazon S3とCloudFrontからCloudflare R2へ
移した記録であり、個人ブログのスタティックなリソースを
どこに置くべきかを考える材料でもあります。
</summary>
        </entry><entry xml:lang="en">
        <title>ChatGPT Images 2.0と、ブログのカバー画像パイプライン更新</title>
        <published>2026-05-15T20:00:00+09:00</published>
        <updated>2026-05-15T20:00:00+09:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2026/05/chatgpt-images-2-0/" type="text/html"/>
        <id>https://codedchords.dev/blog/2026/05/chatgpt-images-2-0/</id>
        
            <content type="html">&lt;!-- textlint-disable --&gt;
&lt;img
  src=&quot;https:&amp;#x2F;&amp;#x2F;codedchords.dev&amp;#x2F;blog&amp;#x2F;2026&amp;#x2F;05&amp;#x2F;chatgpt-images-2-0&amp;#x2F;cover.webp?h=2ba98580c0d5e882e1a8&quot;
  alt=&quot;Cover&quot; width=&quot;1536&quot; height=&quot;864&quot; loading=&quot;lazy&quot;
&#x2F;&gt;&lt;!-- textlint-enable --&gt;
&lt;p&gt;OpenAIは2026年4月21日、新しい画像生成モデルChatGPT Images 2.0を発表しました。API名は &lt;code&gt;gpt-image-2&lt;&#x2F;code&gt; で、開発者向けには5月初旬から開放されています。私のブログではカバー画像の自動生成に旧モデル &lt;code&gt;gpt-image-1&lt;&#x2F;code&gt; を使っていたので、乗り換える価値があるかを調べた上で、今回のリリースに合わせて実際に移行しました。本稿では、新モデルで何が変わったか、料金へのインパクト、そして自分のブログでの乗り換え作業をまとめます。&lt;&#x2F;p&gt;
&lt;span id=&quot;continue-reading&quot;&gt;&lt;&#x2F;span&gt;&lt;details&gt;
&lt;summary&gt;Table of Contents&lt;&#x2F;summary&gt;
&lt;!-- toc --&gt;
&lt;&#x2F;details&gt;
&lt;h2 id=&quot;ChatGPT_Images_2.0で何が変わったか&quot;&gt;ChatGPT Images 2.0で何が変わったか&lt;&#x2F;h2&gt;
&lt;p&gt;ChatGPT Images 2.0の特徴は、画像生成に「考えてから描く」という工程が入ったことです。プロンプトを受け取ったあとに構図やレイアウトを推論で組み立て、必要に応じて自己検証を挟んでから描画に進みます。OpenAI自身は「Agentic image generation」と表現しており、テキストから画像へのワンショット変換とは異なる挙動を示します。&lt;&#x2F;p&gt;
&lt;p&gt;実務面で効いてくる改良点を並べると次のようになります。&lt;&#x2F;p&gt;
&lt;dl&gt;
&lt;dt&gt;テキスト描画の精度向上&lt;&#x2F;dt&gt;
&lt;dd&gt;看板・図表・タイトルなど、画像内の文字を読める品質で出せるようになりました。印刷物にも耐える水準とされています。&lt;&#x2F;dd&gt;
&lt;dt&gt;ネイティブ2K解像度&lt;&#x2F;dt&gt;
&lt;dd&gt;2048x2048を素のままで生成でき、有料プランでは4Kまでのアップスケールが選べます。前世代の引き伸ばし感は減りました。&lt;&#x2F;dd&gt;
&lt;dt&gt;自由なアスペクト比&lt;&#x2F;dt&gt;
&lt;dd&gt;3:1から1:3までの範囲で、16の倍数を満たす任意のサイズを指定できます。固定プリセットから連続パラメータへの転換です。&lt;&#x2F;dd&gt;
&lt;dt&gt;マルチイメージのバッチ生成&lt;&#x2F;dt&gt;
&lt;dd&gt;&lt;code&gt;n=1〜8&lt;&#x2F;code&gt; でキャラクターやオブジェクトの一貫性を保ったまま、最大8枚を同時生成できます。&lt;&#x2F;dd&gt;
&lt;&#x2F;dl&gt;
&lt;p&gt;なお「Thinking mode」と呼ばれる、Web検索を生成中に挟んで結果を補強する追加機能はChatGPT本体のPlus・Pro・Business・Enterpriseプランに限定されています。APIから素直に呼び出した場合に同等の挙動が得られるかは現時点で公開情報からは判然としません。日常的なカバー画像生成では恩恵が薄いため、本稿では深掘りしません。&lt;&#x2F;p&gt;
&lt;p&gt;合わせて、旧世代モデルのDALL·E 2およびDALL·E 3は2026年5月12日付で廃止されています。&lt;code&gt;gpt-image-1&lt;&#x2F;code&gt; 自体の廃止は告知されていませんが、明確に前世代の位置づけになりました。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;料金面のインパクト&quot;&gt;料金面のインパクト&lt;&#x2F;h2&gt;
&lt;p&gt;OpenAIの画像APIは、出力トークンに対する従量課金($30.00&#x2F;100万トークン)を基準に、サイズと品質ごとに代表的な価格が公表されています。私のブログでは1536x1024&#x2F;高品質を使っていたので、その線で比較します。&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th style=&quot;text-align: left&quot;&gt;解像度 &#x2F; 品質&lt;&#x2F;th&gt;&lt;th style=&quot;text-align: left&quot;&gt;gpt-image-1&lt;&#x2F;th&gt;&lt;th style=&quot;text-align: left&quot;&gt;gpt-image-2&lt;&#x2F;th&gt;&lt;th style=&quot;text-align: left&quot;&gt;差分&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;1024x1024 &#x2F; high&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;$0.167&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;$0.211&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;+26%&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;1536x1024 &#x2F; high(旧設定)&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;$0.25&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;$0.165&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;&lt;strong&gt;-34%&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;1536x1024 &#x2F; medium&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;$0.063&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;$0.041&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;-35%&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;1536x1024 &#x2F; low&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;$0.016&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;$0.005&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;-69%&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;興味深いのは、&lt;code&gt;gpt-image-2&lt;&#x2F;code&gt; では1024x1024より1536x1024のほうが安いという逆転が起きている点です。&lt;code&gt;gpt-image-2&lt;&#x2F;code&gt; は連続的なサイズ指定とトークンベースの課金に振り切ったため、画素数と価格の関係が必ずしも単調ではなくなりました。これは料金表というよりトークン課金の写像として読むべきもので、サイズによる単純な大小比較は通用しなくなっています。&lt;&#x2F;p&gt;
&lt;p&gt;絶対額で見ると、記事1本あたり$0.085ほどの削減です。年に50本書いても$4程度なので、コスト最適化自体が主目的にはなりません。ただし「安くなって性能が上がる」方向の更新であり、乗り換えを見送る理由はありません。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;output_format=webp_のバグ&quot;&gt;&lt;code&gt;output_format=webp&lt;&#x2F;code&gt; のバグ&lt;&#x2F;h2&gt;
&lt;p&gt;実装中に確認したところ、&lt;code&gt;gpt-image-2&lt;&#x2F;code&gt; は &lt;code&gt;output_format=webp&lt;&#x2F;code&gt; を指定しても、実際にはPNGデータを返してきます。レスポンスJSONには &lt;code&gt;&quot;output_format&quot;: &quot;webp&quot;&lt;&#x2F;code&gt; が含まれているものの、&lt;code&gt;b64_json&lt;&#x2F;code&gt; をデコードすると先頭が &lt;code&gt;89 50 4E 47 0D 0A 1A 0A&lt;&#x2F;code&gt; のPNGシグネチャになっています。&lt;&#x2F;p&gt;
&lt;p&gt;同一パラメータを &lt;code&gt;gpt-image-1&lt;&#x2F;code&gt; に渡した場合は正しくWebPが返るため、現時点では &lt;code&gt;gpt-image-2&lt;&#x2F;code&gt; 固有の不具合と判断しています。&lt;&#x2F;p&gt;
&lt;p&gt;そのため、本記事で示すスクリプトではAPIレスポンスをPNGとして受け取り、内部で &lt;code&gt;cwebp -q 80&lt;&#x2F;code&gt; によりWebPへ再エンコードしています。呼び出し側インターフェースは変更せず、最終的には1536x864のWebPファイルを取得できます。&lt;&#x2F;p&gt;
&lt;p&gt;OpenAI側で修正された場合は、&lt;code&gt;output_format=webp&lt;&#x2F;code&gt; をそのまま利用し、内部変換ステップを削除する想定です。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;ブログのパイプラインを乗り換える&quot;&gt;ブログのパイプラインを乗り換える&lt;&#x2F;h2&gt;
&lt;p&gt;私のブログではカバー画像を &lt;code&gt;scripts&#x2F;generate-cover.sh&lt;&#x2F;code&gt; からOpenAI Image APIを叩いて生成しています。これまでは &lt;code&gt;gpt-image-1&lt;&#x2F;code&gt; から1536x1024のPNGを受け取り、&lt;code&gt;cwebp -q 80&lt;&#x2F;code&gt; でWebPに変換して &lt;code&gt;cover.webp&lt;&#x2F;code&gt; を作っていました。新モデルへの移行で、このパイプラインが得る恩恵は大きく2点あります。&lt;&#x2F;p&gt;
&lt;dl&gt;
&lt;dt&gt;画像精度の底上げ&lt;&#x2F;dt&gt;
&lt;dd&gt;テキスト描画・構図・解像度がモデルレベルで改善するため、カバー画像の見栄えが直接良くなります。&lt;code&gt;gpt-image-1&lt;&#x2F;code&gt; とのAPI互換性が高く、エンドポイント・認証・レスポンス形式(&lt;code&gt;b64_json&lt;&#x2F;code&gt;)はそのまま使えるため、これだけなら &lt;code&gt;MODEL&lt;&#x2F;code&gt; 変数を &lt;code&gt;gpt-image-2&lt;&#x2F;code&gt; に書き換えれば享受できます。&lt;&#x2F;dd&gt;
&lt;dt&gt;画角の自由度&lt;&#x2F;dt&gt;
&lt;dd&gt;画角16:9で指定できるようになりました。&lt;code&gt;gpt-image-2&lt;&#x2F;code&gt; のサイズパラメータは「16の倍数」「総画素数65万〜829万」「縦横比3:1〜1:3」を満たす任意の値を受け付けるため、1536x864のような正確な16:9に直接出力できます。旧モデルのプリセット制約から3:2(1536x1024)に妥協していた本ブログでは、記事一覧の見栄えとX(旧Twitter)・はてなブックマークなどのSNSカードプレビューの収まりが、ようやく現代のプラットフォームと噛み合うようになりました。&lt;&#x2F;dd&gt;
&lt;&#x2F;dl&gt;
&lt;p&gt;リクエスト本体は次のようになりました。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot; data-name=&quot;scripts&#x2F;generate-cover.sh&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;SIZE&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;1536x864&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;MODEL&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;gpt-image-2&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;RESPONSE&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;$(&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;curl&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; -s&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;  https:&#x2F;&#x2F;api.openai.com&#x2F;v1&#x2F;images&#x2F;generations&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt;  -H &amp;quot;Content-Type: application&#x2F;json&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt;  -H &amp;quot;Authorization: Bearer &lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-normal z-shell&quot;&gt;$OPENAI_API_KEY&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt;  -d &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;$(&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;jq&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; -n&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt;    --arg model &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-normal z-shell&quot;&gt;$MODEL&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt;    --arg prompt &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-normal z-shell&quot;&gt;$PROMPT&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt;    --arg size &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-normal z-shell&quot;&gt;$SIZE&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt;    --arg quality &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-normal z-shell&quot;&gt;$QUALITY&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;    &amp;#39;{model: $model, prompt: $prompt, n: 1,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt;      size: $size, quality: $quality}&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;このスクリプトを呼び出している &lt;code&gt;article-cover&lt;&#x2F;code&gt; スキル(Claude Code用のカスタムコマンド)の全体は次のとおりです。記事の特定からフロントマター確認までを4ステップで定義しており、&lt;code&gt;gpt-image-2&lt;&#x2F;code&gt; への移行に際しての変更は不要でした。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;markdown&quot; data-name=&quot;.claude&#x2F;commands&#x2F;article-cover.md&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;---&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;description&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; Generate a cover image for an article using OpenAI gpt-image-2 API. Read article content, craft a prompt, generate 1536x864 (16:9) WebP image.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;---&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-heading z-markdown z-heading z-\31  z-markdown&quot;&gt;# Article Cover Image Generation&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;Generate a cover image (cover.webp) for an article using OpenAI gpt-image-2 API.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-heading z-markdown z-heading z-\32  z-markdown&quot;&gt;## Steps&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-heading z-markdown z-heading z-\33  z-markdown&quot;&gt;### 1. Identify Target Article&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;Ask the user which article to generate a cover image for.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;Read the article content to understand the theme and key topics.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-heading z-markdown z-heading z-\33  z-markdown&quot;&gt;### 2. Craft Image Prompt&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;Based on the article content:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-list z-begin z-markdown&quot;&gt;-&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt; Identify the core theme and visual concepts&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-list z-begin z-markdown&quot;&gt;-&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt; Craft a gpt-image-2 prompt that captures the article&amp;#39;s essence&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-list z-begin z-markdown&quot;&gt;-&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt; Show the prompt to the user for approval before generating&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-heading z-markdown z-heading z-\33  z-markdown&quot;&gt;### 3. Generate Image&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;Run &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-raw z-markdown z-markup z-inline z-raw z-string z-markdown&quot;&gt;`.&#x2F;scripts&#x2F;generate-cover.sh`&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition&quot;&gt;```&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;.&#x2F;scripts&#x2F;generate-cover.sh \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;  -p &amp;quot;&amp;lt;approved prompt&amp;gt;&amp;quot; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;  -o content&#x2F;blog&#x2F;YYYY&#x2F;MM&#x2F;slug&#x2F;cover.webp&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition&quot;&gt;```&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;The script defaults to 1536x864 (16:9), high quality, and WebP output.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-heading z-markdown z-heading z-\33  z-markdown&quot;&gt;### 4. Verify Frontmatter&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;Ensure the article frontmatter has:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition&quot;&gt;```&lt;&#x2F;span&gt;&lt;span class=&quot;z-fenced_code z-block z-language&quot;&gt;toml&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;[extra]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;local_image = &amp;quot;cover.webp&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;social_media_card = &amp;quot;ogp.webp&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition&quot;&gt;```&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;本記事のカバー画像も、この新しいパイプラインで生成しました。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;まとめ&quot;&gt;まとめ&lt;&#x2F;h2&gt;
&lt;p&gt;ChatGPT Images 2.0は、価格が下がり、解像度とアスペクト比の選択肢が広がった、素直なアップグレードでした。&lt;code&gt;gpt-image-1&lt;&#x2F;code&gt; を呼んでいる既存コードであれば、&lt;code&gt;model&lt;&#x2F;code&gt; を差し替えるだけで動き始めます。&lt;&#x2F;p&gt;
&lt;p&gt;連続的なサイズ指定や推論を伴う構図設計といった点は、定型的なカバー画像生成だけでなく、SNS向け縦長フォーマットや図解付き画像など、これまで複数モデルを使い分けていた領域も &lt;code&gt;gpt-image-2&lt;&#x2F;code&gt; 1本に集約しうるポテンシャルを持ちます。エージェント型ワークフローからの呼び出しでも、複数枚の一貫した出力をシングルリクエストで得られる点が効いてきそうです。&lt;&#x2F;p&gt;
&lt;p&gt;しばらくこのパイプラインを運用してみて、生成品質や絵柄の傾向で気になる点、あるいは &lt;code&gt;output_format=webp&lt;&#x2F;code&gt; まわりの挙動に変化があれば、別途取り上げます。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;References&quot;&gt;References&lt;&#x2F;h2&gt;
&lt;div class=&quot;references&quot;&gt;
    &lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;openai.com&#x2F;index&#x2F;introducing-chatgpt-images-2-0&#x2F;&quot;&gt;OpenAI&lt;&#x2F;a&gt;.「Introducing ChatGPT Images 2.0」&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;developers.openai.com&#x2F;api&#x2F;docs&#x2F;models&#x2F;gpt-image-1&quot;&gt;OpenAI API Docs&lt;&#x2F;a&gt;.「GPT Image 1 Model」(価格比較用)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;openai.com&#x2F;api&#x2F;pricing&#x2F;&quot;&gt;OpenAI API Pricing&lt;&#x2F;a&gt;.「OpenAI API Pricing」&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;techcrunch.com&#x2F;2026&#x2F;04&#x2F;21&#x2F;chatgpts-new-images-2-0-model-is-surprisingly-good-at-generating-text&#x2F;&quot;&gt;TechCrunch&lt;&#x2F;a&gt;.「ChatGPT&#x27;s new Images 2.0 model is surprisingly good at generating text」&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;thenewstack.io&#x2F;chatgpt-images-20-openai&#x2F;&quot;&gt;The New Stack&lt;&#x2F;a&gt;.「With the launch of ChatGPT Images 2.0, OpenAI now &#x27;thinks&#x27; before it draws」&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;

&lt;&#x2F;div&gt;
</content>
        <summary type="html">OpenAIが2026年4月21日にリリースしたChatGPT Images 2.0は、画像生成に推論能力を組み込んだ新世代のモデルです。1536x864&#x2F;高品質で料金は約34%下がり、ネイティブ2K解像度や3:1から1:3までの自由なアスペクト比も使えるようになりました。本ブログのカバー画像生成パイプラインも、このタイミングで乗り換えました。</summary>
        </entry><entry xml:lang="en">
        <title>Claude Platform on AWSに見る新時代のハイパースケーラー</title>
        <published>2026-05-13T20:00:00+09:00</published>
        <updated>2026-05-13T20:00:00+09:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2026/05/claude-platform-aws/" type="text/html"/>
        <id>https://codedchords.dev/blog/2026/05/claude-platform-aws/</id>
        
            <content type="html">&lt;!-- textlint-disable --&gt;
&lt;img
  src=&quot;https:&amp;#x2F;&amp;#x2F;codedchords.dev&amp;#x2F;blog&amp;#x2F;2026&amp;#x2F;05&amp;#x2F;claude-platform-aws&amp;#x2F;cover.webp?h=8abf7062e68c7aef84c7&quot;
  alt=&quot;Cover&quot; width=&quot;1536&quot; height=&quot;1024&quot; loading=&quot;lazy&quot;
&#x2F;&gt;&lt;!-- textlint-enable --&gt;
&lt;p&gt;2026年5月11日、AnthropicとAWSは「Claude Platform on AWS」を一般提供開始しました。Anthropic本家のMessages APIやConsoleの体験そのものを、AWSアカウントから直接利用できる新しい入口で、東京リージョンも初日から対応しています。ただし本稿で読み解きたいのは、機能の追加そのものではなく、この発表が示すAWSの立ち位置の構造的な変化です。Bedrockとの違い、Cloud 2.0レイヤーでの位置づけ、AWS提案の現場への影響という3つの角度から見ていきます。&lt;&#x2F;p&gt;
&lt;span id=&quot;continue-reading&quot;&gt;&lt;&#x2F;span&gt;&lt;details&gt;
&lt;summary&gt;Table of Contents&lt;&#x2F;summary&gt;
&lt;!-- toc --&gt;
&lt;&#x2F;details&gt;
&lt;h2 id=&quot;Claude_Platform_on_AWSとは何か&quot;&gt;Claude Platform on AWSとは何か&lt;&#x2F;h2&gt;
&lt;p&gt;新サービスの概要は次のとおりです。Anthropicが運用するClaude Platformそのものを、AWSアカウントの認証情報と請求経路を介して利用できるようにしたものです。利用者から見えるエンドポイントもSDKの作法も、Anthropic本家のそれとほぼ共通しています。&lt;&#x2F;p&gt;
&lt;p&gt;具体的には、SDKに &lt;code&gt;ANTHROPIC_BASE_URL=https:&#x2F;&#x2F;aws-external-anthropic.&amp;lt;region&amp;gt;.api.aws&lt;&#x2F;code&gt; と &lt;code&gt;anthropic-workspace-id&lt;&#x2F;code&gt; ヘッダーを設定するだけで、Anthropic向けに書いたコードがそのままAWS経路で動きます。認証はAWSのIAM資格情報で行ない、別途Anthropicアカウントを取る必要はありません。利用料はAWS Marketplace経由で計上され、Cost Explorerでモニタリングでき、Enterprise Discount ProgramなどのAWSコミット消化対象にもなります。&lt;&#x2F;p&gt;
&lt;p&gt;使える機能はAnthropic本家とほぼ同等です。Messages APIから最新のエージェント関連機能まで一通り揃い、モデルもClaude Opus 4.7、Sonnet 4.6、Haiku 4.5を同日提供しています。新モデルや新機能がリリース当日(Day-0)から使えるという点こそ、これまでBedrock側の取り込みを待たされてきた構図が崩れた、今回の本質的な変化です。&lt;&#x2F;p&gt;
&lt;p&gt;監査はCloudTrailのManagement Eventsがデフォルトで記録され、推論呼び出しそのものはオプションでData Eventsとして流せます。&lt;&#x2F;p&gt;
&lt;!-- textlint-disable --&gt;
&lt;aside data-position=&quot;right&quot;&gt;
    &lt;p&gt;Workspaceは、APIキー・権限・課金・月次上限を環境やチーム単位で分離できる、Anthropic Console固有の論理単位です。&lt;&#x2F;p&gt;

&lt;&#x2F;aside&gt;
&lt;!-- textlint-enable --&gt;
&lt;p&gt;もう一点、Workspaceという新しい概念が入りました。これはプロジェクト・環境・チームを切り分けつつ請求単位も分けられるIAMリソースで、Anthropic Consoleにあるワークスペースの仕組みをAWS IAMの語彙で組み込んだものです。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;Bedrockと何が違うのか&quot;&gt;Bedrockと何が違うのか&lt;&#x2F;h2&gt;
&lt;p&gt;AnthropicのモデルならBedrock経由で既に使えるのに、なぜ別の経路を用意したのか。本サービスをBedrockと比較したときのPros&#x2F;Consは次のとおりです。&lt;&#x2F;p&gt;
&lt;dl&gt;
&lt;dt&gt;Pros&lt;&#x2F;dt&gt;
&lt;dd&gt;AWSの統制・監査基盤の上で、Anthropic本家とほぼ同等の機能と最新モデルをDay-0で使える。&lt;&#x2F;dd&gt;
&lt;dt&gt;Cons&lt;&#x2F;dt&gt;
&lt;dd&gt;データがAWS外で扱われるため別建てのデータ管理が必要になる。加えてClaude専用のため、マルチモデル戦略は取れない。&lt;&#x2F;dd&gt;
&lt;&#x2F;dl&gt;
&lt;p&gt;機能面の違いを並べると次のとおりです。&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th style=&quot;text-align: left&quot;&gt;観点&lt;&#x2F;th&gt;&lt;th style=&quot;text-align: left&quot;&gt;Amazon Bedrock&lt;&#x2F;th&gt;&lt;th style=&quot;text-align: left&quot;&gt;Claude Platform on AWS&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;推論データの処理者・処理境界&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;AWS(AWS境界内)&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;Anthropic(AWS境界外)&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;新モデル・新機能の追随&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;数週〜数か月遅れ&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;Day-0で揃う&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;モデルベンダー多様性&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;多ベンダー(十数社)&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;Claudeのみ&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;AWS IAM &#x2F; Marketplace &#x2F; CloudTrail&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;統合あり&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;統合あり&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;違いは大きく分けて、データの境界と機能の追随速度という2点に集約できます。&lt;&#x2F;p&gt;
&lt;p&gt;Bedrockの構造では、AWSが推論基盤までを自社で運用し、データ処理者としての責任を負います。推論はAWSのセキュリティ境界の内側で行われ、入力データはAnthropicへは共有されません。推論にAWSのデータ統制を要求するエンタープライズ用途に向いた構造です。&lt;&#x2F;p&gt;
&lt;p&gt;一方、Claude Platform on AWSは、認証と請求と監査こそAWSが提供しますが、推論サービス自体はAnthropicが運用する基盤で動きます。データはAWSのセキュリティ境界の外側、Anthropicの管理下で処理されます。この差はコンプライアンス上、本質的です。データレジデンシーやAWS境界内処理を契約で求めている組織には、Bedrockのほうが依然として現実解です。&lt;&#x2F;p&gt;
&lt;p&gt;逆に、Anthropicが最新モデルや新機能をリリースした瞬間からそれを使いたい組織には、Claude Platform on AWSが勝ります。Bedrockでは、Anthropic本家のAPIで先行した機能(extended thinkingやFiles APIなど)が、AWS側のコモディティ化を経て登場するまで数週間から数か月のラグが生じることも珍しくありませんでした。今回のサービスは、その間隙を埋める性格のものです。&lt;&#x2F;p&gt;
&lt;p&gt;選択軸が「データ境界と機能の速さ、どちらを優先するか」に整理されてきたことが分かります。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;AIサービスにおけるAWSの役回りの変化&quot;&gt;AIサービスにおけるAWSの役回りの変化&lt;&#x2F;h2&gt;
&lt;p&gt;ここからが本稿の本題です。新サービスを技術仕様として眺める以上に、AWSがどんな役回りを引き受けたのかという視点で見るほうが示唆に富みます。&lt;&#x2F;p&gt;
&lt;p&gt;Claude Platform on AWSが構造的に行っているのは、レイヤーの分離です。推論というサービス本体はAnthropicの外部基盤に置きつつ、認証(IAM)、請求(Marketplace)、監査(CloudTrail)、コミット消化といった企業ガバナンスの足回りだけをAWSが提供しています。&lt;&#x2F;p&gt;
&lt;p&gt;この構造は、Cloudflare Workersに &lt;code&gt;ANTHROPIC_API_KEY&lt;&#x2F;code&gt; を環境変数で渡して、Anthropic本家のAPIを叩いているのと本質的に変わりません。違いは、認証がAPIキーではなくIAMで、請求がクレジットカードではなくAWS請求書で、ログがWorkers TraceではなくCloudTrailであることです。エンタープライズの調達と監査の要件を満たすかどうかという、その一点だけが違います。&lt;&#x2F;p&gt;
&lt;p&gt;ここでAWSが押さえている価値は、コンピュートやストレージではありません。請求と身元と監査ログを束ねる「企業の窓口」としての地位です。AWSはこれまで、Cloud 1.0期に積み上げた抽象化レイヤー、つまりEC2やS3やLambdaといったプリミティブで稼いできました。今回はそれと並行して、自社では運用していない外部の推論サービスの請求と統制を引き受けるという、新しい収益面を開いています。&lt;&#x2F;p&gt;
&lt;p&gt;これは戦略的譲歩なのか、新収益モデルなのか。私の見立ては、両面を同時に成立させる賢い設計、というところです。譲歩の側面はあります。AnthropicのモデルをBedrockに統合してきたこれまでの路線とは異なり、推論基盤の主導権をAnthropic側に残したまま窓口だけ引き受ける形だからです。一方でAWSは、Enterprise Discount Programの消化先を増やせますし、新モデル待ちでAWSを離れる顧客を引き留められます。失う主導権の代わりに、エンタープライズの窓口という地位を補強する取引です。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;Cloud_0.5&#x2F;1.0&#x2F;2.0で見るとどこに位置するか&quot;&gt;Cloud 0.5&#x2F;1.0&#x2F;2.0で見るとどこに位置するか&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;codedchords.dev&#x2F;blog&#x2F;2026&#x2F;04&#x2F;cloud2-0&#x2F;&quot;&gt;以前の記事&lt;&#x2F;a&gt;で、Cloudの時代区分を「Cloud 0.5(仮想化インフラ)」「Cloud 1.0(Cloud Native)」「Cloud 2.0(Agentic Cloud)」の3段で整理しました。Claude Platform on AWSはこの枠組みのどこに位置づけられるでしょうか。&lt;&#x2F;p&gt;
&lt;!-- textlint-disable --&gt;
&lt;aside data-position=&quot;right&quot;&gt;
    &lt;p&gt;本記事における「Cloud 2.0」の定義: LLMエージェントがCloudのワークロードの主役となる新しいレイヤーを指す、本記事独自の用語として用います。&lt;&#x2F;p&gt;

&lt;&#x2F;aside&gt;
&lt;!-- textlint-enable --&gt;
&lt;p&gt;Cloud 1.0期のハイパースケーラーは、抽象化レイヤーの提供者でした。物理インフラを覆い隠して、IAMやVPCやマネージドサービスといったプリミティブを通じて開発者に売る役割です。AWSがその役割で群を抜いたことが、Cloud 1.0時代の覇権をもたらしました。&lt;&#x2F;p&gt;
&lt;p&gt;Cloud 2.0期に入ると、ワークロードの主役はLLMエージェントになります。エージェントは、推論基盤、軽量実行環境、永続記憶、版管理ストレージといったプリミティブを使い倒します。ここで重要なのは、これらのプリミティブを必ずしも一社で提供する必要はないという点です。エージェントは複数のサービス境界を越えて動きますし、エンタープライズが推論をAnthropicに、実行環境をCloudflareに、ストレージをAWSにというような組み合わせを選ぶことも当たり前になりつつあります。&lt;&#x2F;p&gt;
&lt;p&gt;そう考えると、前節で論じたAWSの役回り変化は、Cloud 2.0レイヤー全体に起きている地殻変動の一場面として位置づけられます。Cloud 1.0期に培った企業ガバナンス基盤を、自社で運用しない外部の推論サービスにも貸し出す。これが今、Cloud 2.0レイヤーでハイパースケーラーが取りうる役回りのひとつで、Bedrockを併存させているのは内製と外部窓口の両方をAWSが押さえにいくという意思の表れです。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;AWS提案の現場で起きる変化&quot;&gt;AWS提案の現場で起きる変化&lt;&#x2F;h2&gt;
&lt;p&gt;ここから少し業界寄りの話です。AWSのソリューション提案を生業にしてきた人々への影響を見ておきます。&lt;&#x2F;p&gt;
&lt;p&gt;これまでのBedrock案件では、「Anthropic、OpenAI、Meta、Mistralを統一APIで使い分けられる」というマルチモデル統合の価値が前面に出てきました。データレジデンシーやIAM統合と並んで、Bedrockを選ぶ理由のひとつとして語られてきた論点です。&lt;&#x2F;p&gt;
&lt;p&gt;Claude Platform on AWSの登場は、このうち「Anthropicの最新モデルを使いたい」という需要を、Bedrock以外で吸収できることを意味します。Claudeしか使わないユースケースに対しては、「Bedrockでマルチモデルを集約する」という売り文句の説得力が下がります。同じAWSの中に、Anthropic直叩きと変わらない経路が用意されたからです。&lt;&#x2F;p&gt;
&lt;p&gt;提案のロジックも組み替えが要ります。要件ごとの選択は次のように整理できます。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;データレジデンシーやAWS境界内処理が契約上の必須要件 → Bedrock&lt;&#x2F;li&gt;
&lt;li&gt;Day-0でClaudeの新機能を使いたい、またはWorkspace単位の請求分離が必要 → Claude Platform on AWS&lt;&#x2F;li&gt;
&lt;li&gt;複数モデルベンダーをユースケース別に使い分けたい → Bedrock&lt;&#x2F;li&gt;
&lt;li&gt;ClaudeとOpenAIの両方を本家経路で使いたい → BedrockとClaude Platform on AWSの併用&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;選択軸が一段細かくなりました。&lt;&#x2F;p&gt;
&lt;p&gt;元AWS ProServeの目で見ると、これは案件の議論を健全にする方向の変化です。Bedrockを「とりあえずの安全牌」として薦める提案には、本来の要件と噛み合わないものが含まれていました。選択肢が増えたことで、データ境界要件か機能の追随速度かを正面から議論できるようになります。&lt;&#x2F;p&gt;
&lt;p&gt;逆に、SI側の付加価値の置き場所は前より難しくなります。「マルチモデル統合のための設計」だけでは差別化が薄まり、業務要件を踏まえてどちらの経路を選ぶか、両者をどう使い分けるかという、より上位の意思決定支援に価値が移っていきます。Cloud 1.0期にインフラ選定で稼いだロジックは、Cloud 2.0期には設計者・選定者の判断力という形に少しずつ姿を変えています。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;Anthropicのキャパシティ戦略との符合&quot;&gt;Anthropicのキャパシティ戦略との符合&lt;&#x2F;h2&gt;
&lt;p&gt;最後に、Anthropic側からこの取引を眺めておきます。&lt;&#x2F;p&gt;
&lt;p&gt;Anthropicは2026年に入ってから、AWSと$100Bを超える複数年コンピュート契約を交わし、5GW級のTrainium容量にコミットすると発表しています。一方でMicrosoft AzureやGoogle Cloudとも並行して提携を結んでおり、推論キャパシティを複数のハイパースケーラーに分散させる戦略を取っています。&lt;&#x2F;p&gt;
&lt;!-- textlint-disable --&gt;
&lt;aside data-position=&quot;right&quot;&gt;
    &lt;p&gt;TrainiumはAWSが自社開発するAI学習・推論用カスタムチップです。Nvidia GPUへの依存を減らす狙いがあり、Anthropicの大型契約はその外販ボリュームの一翼を担います。&lt;&#x2F;p&gt;

&lt;&#x2F;aside&gt;
&lt;!-- textlint-enable --&gt;
&lt;p&gt;このキャパシティを最終的に消費するのは、世界中のエンタープライズが回す推論ワークロードです。Anthropic本家APIだけでは、その消費を支えるだけの調達経路を企業に提供しきれません。クレジットカードでの直接契約は、ガバナンスの観点でエンタープライズが選びにくい経路だからです。&lt;&#x2F;p&gt;
&lt;p&gt;Claude Platform on AWSは、Anthropicからすれば「エンタープライズの調達窓口」を一気に拡張する装置です。AWSアカウントを持っている企業の調達担当は、新しいベンダーを通すことなく、既存のMarketplace経由でClaudeを使い始められます。Anthropicは推論基盤の主導権を保ったまま、AWSのエンタープライズ顧客基盤に直結できます。&lt;&#x2F;p&gt;
&lt;p&gt;AWS側から見れば、AnthropicがTrainiumに払うコンピュート料金が、別経路でエンタープライズ向けの推論売上として戻ってきます。Anthropicが請求の上流、AWSが下流という関係です。両者は競合ではなく、調達面で組み合っている構造になっています。&lt;&#x2F;p&gt;
&lt;p&gt;ここまで読むと、Claude Platform on AWSは単発のサービス発表というよりも、Anthropicの分散キャパシティ戦略とAWSの窓口ポジション戦略が噛み合った結果として出てきた仕組みであることが見えてきます。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;まとめ&quot;&gt;まとめ&lt;&#x2F;h2&gt;
&lt;p&gt;Claude Platform on AWSは、機能カタログの一行というよりも、ハイパースケーラーの役回りが変わりつつあることを示す構造的なサインだと感じています。&lt;&#x2F;p&gt;
&lt;p&gt;Bedrockがそうであるように、AWSは引き続き「自社の推論基盤を売る側」でもあります。同時に、外部ベンダーの推論サービスに対して「請求と身元と監査の窓口」を引き受ける役割も併せ持つようになりました。Cloud 1.0期に培った企業ガバナンスの足回りが、Cloud 2.0期では別のベンダーの実行レイヤーを支える土台として再利用されています。&lt;&#x2F;p&gt;
&lt;p&gt;エンタープライズの調達担当やSIの提案担当にとっては、選択肢が増えた分だけ判断軸を明確にする必要が出てきます。データ境界要件か、機能の追随速度か、ベンダー多様性か。それぞれの要件に対して、Bedrock、Claude Platform on AWS、あるいは両者の併用という選択を素直に評価できるようになりました。&lt;&#x2F;p&gt;
&lt;p&gt;今後、同じ仕組みでOpenAIやGoogleがAWS上に乗ってくる可能性も含めて、ハイパースケーラーの窓口化はゆっくりと進む流れだと見ています。Cloud 2.0期にAWSがどの地位を確保するのか、その答えのひとつがこの発表に入っているのではないでしょうか。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;References&quot;&gt;References&lt;&#x2F;h2&gt;
&lt;div class=&quot;references&quot;&gt;
    &lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;aws.amazon.com&#x2F;blogs&#x2F;machine-learning&#x2F;introducing-claude-platform-on-aws-anthropics-native-platform-through-your-aws-account&#x2F;&quot;&gt;AWS Machine Learning Blog&lt;&#x2F;a&gt;.「Introducing Claude Platform on AWS, Anthropic&#x27;s native platform through your AWS account」&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;aws.amazon.com&#x2F;claude-platform&#x2F;&quot;&gt;AWS&lt;&#x2F;a&gt;.「Claude Platform on AWS」(製品ページ)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;aws.amazon.com&#x2F;about-aws&#x2F;whats-new&#x2F;2026&#x2F;05&#x2F;claude-platform-aws&#x2F;&quot;&gt;AWS What&#x27;s New&lt;&#x2F;a&gt;.「Claude Platform on AWS is now generally available」&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.anthropic.com&#x2F;news&#x2F;anthropic-amazon-compute&quot;&gt;Anthropic&lt;&#x2F;a&gt;.「Anthropic and Amazon expand collaboration for up to 5GW of Trainium compute」(2026年4月20日)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.aboutamazon.com&#x2F;news&#x2F;company-news&#x2F;amazon-invests-additional-5-billion-anthropic-ai&quot;&gt;About Amazon&lt;&#x2F;a&gt;.「Amazon and Anthropic expand strategic collaboration」&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;

&lt;&#x2F;div&gt;
</content>
        <summary type="html">2026年5月11日にGAされたClaude Platform on AWSは、AnthropicのネイティブAPIをAWSアカウントから直接呼べる新サービスです。この発表が示すAWSの立ち位置の構造的な変化を、Bedrockとの違い、Cloud 2.0レイヤー、AWS提案現場の3つの角度から読み解きます。</summary>
        </entry><entry xml:lang="en">
        <title>読了『闘うプログラマー』</title>
        <published>2026-05-12T07:33:12+09:00</published>
        <updated>2026-05-12T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2026/05/showstopper/" type="text/html"/>
        <id>https://codedchords.dev/blog/2026/05/showstopper/</id>
        
            <content type="html">&lt;!-- textlint-disable --&gt;
&lt;img
  src=&quot;https:&amp;#x2F;&amp;#x2F;codedchords.dev&amp;#x2F;blog&amp;#x2F;2026&amp;#x2F;05&amp;#x2F;showstopper&amp;#x2F;cover.webp?h=20edf939cee5cd3ca20f&quot;
  alt=&quot;Cover&quot; width=&quot;1536&quot; height=&quot;1024&quot; loading=&quot;lazy&quot;
&#x2F;&gt;&lt;!-- textlint-enable --&gt;
&lt;details&gt;
&lt;summary&gt;Table of Contents&lt;&#x2F;summary&gt;
&lt;!-- toc --&gt;
&lt;&#x2F;details&gt;
&lt;span id=&quot;continue-reading&quot;&gt;&lt;&#x2F;span&gt;
&lt;p&gt;1980年代にMS-DOSでデスクトップパソコン市場を制し、WindowsでGUIのオペレーティング・システム(以降、「OS」と記載)も制しつつあったマイクロソフト社は、90年代、高性能コンピューター向けの「本物」のOS開発プロジェクトを立ち上げます。当時のマイクロソフト社の世界戦略を担ったOS「WindowsNT」です。そのプロジェクトに、当時DEC社のミニコン向けOS、VAX&#x2F;VMSの開発者であった「伝説のプログラマー」David Neil Cutlerが招へいされました。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;本書の概要&quot;&gt;本書の概要&lt;&#x2F;h2&gt;
&lt;p&gt;本書は、David Cutlerを中心とした開発物語です。&lt;&#x2F;p&gt;
&lt;p&gt;『闘うプログラマー』というタイトルから、David Cutler中心に描かれていると思って購入しました。冒頭は、彼がDEC社で担当していた新OSプロジェクト「Mica」が破棄され、1988年マイクロソフト社に移籍するシーンから描かれています。前半は彼がいかにWindowsNTプロジェクトを立ち上げたかが描かれていますが、中盤からはこのプロジェクトに参加したあらゆるレイヤーの開発者へと順次フォーカスが当てられ、エピソードが盛り込まれていきます。&lt;&#x2F;p&gt;
&lt;p&gt;全く新しいOSを、当時主流だったIntelのCPUだけでなく、まだ完成していないRISCにも対応させなければなりません。さらにDOSとの互換性、Win32系の旧来のWindowsとの互換性も維持する必要があったわけです。想像するだけでデスマーチな開発ですが、本書を読めば実際にデスマーチだったことが分かります。それでも当時は「Cutlerの元で新しいOSの開発が出来る」ことを栄誉だと考えるプログラマーが多くいたわけです。&lt;&#x2F;p&gt;
&lt;p&gt;Cutlerの伝記として読むと中途半端ですが、当時のWindowsNTの過酷な開発エピソードが盛り込まれている点は大変興味深く読めました。本書がWindowsNTの初版がリリースされた1993年に出版されたため、開発者たちのエピソードも生々しく、リアルな状況を伝えています。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;「OSの時代」を背景に&quot;&gt;「OSの時代」を背景に&lt;&#x2F;h2&gt;
&lt;p&gt;WindowsNTの開発が始まった1980年代後半から1990年代に掛けては、まさに「OSの時代」でした。当時は、ハードウェアやネットワークの環境が大きく変化した時代でもあります。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;CPUは16ビットから32ビットに進化し、RISCという新しいアーキテクチャーも登場した&lt;&#x2F;li&gt;
&lt;li&gt;MacintoshがGUIを一般ユーザーに広めた結果、プリエンプティブなマルチタスクが一般レベルでも要求されるようになった&lt;&#x2F;li&gt;
&lt;li&gt;インターネットの普及により、モデムでのパソコン通信ではなく本格的なネットワーク機能が一般ユーザーでも必要となった&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;PCはMS-DOS上でWindows3.xが動いていましたが、16ビットアーキテクチャーを引きずっていました。IBMは「OS&#x2F;2」という新しいOSをマイクロソフト社と共にリリースしていましたが、コンシューマーの世界では全く浸透していませんでした。Apple社はClassic Mac OSを何度も刷新しようとしていましたが、ことごとく失敗していました。&lt;&#x2F;p&gt;
&lt;p&gt;そんな中で開発されたWindowsNTは、その後Windows2000、WindowsXPとコンシューマー向けWindowsの核となり、最も成功したOSとなっていきました。&lt;&#x2F;p&gt;
&lt;p&gt;私自身、1995年頃に自宅のPCにWindowsNTを導入していました。とはいえ、当時実際に使っていたツールの大半はWindowsベースですらなく、DOSベースのものが中心だったように記憶しています。それでも「本物のOS」に触れられたこと自体はよいお勉強になりましたし、ファイルシステムのNTFSはFATに比べて信頼性が明らかに高く、家庭利用でもその差を実感できました。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;米国でのプログラマーの地位&quot;&gt;米国でのプログラマーの地位&lt;&#x2F;h2&gt;
&lt;p&gt;個人的に印象的だったのは、米国での「プログラマー」の地位です。WindowsNTの開発に参加していた開発者が、皆スタープログラマーという訳ではありませんでした。それでも多くの開発者はストックオプションで一財産を築き、西海岸に家を建てポルシェを購入してという経済的な成功を手に入れています。日本における「プログラマー」の扱いとは大違いです。&lt;&#x2F;p&gt;
&lt;p&gt;翻って日本では、多くのプログラマーがSIer (システムインテグレーター) を頂点とする多重下請け構造の中で受託開発に従事しています。給与水準は一般のサラリーマンと大きく変わらず、ストックオプションで一財産を築くケースは稀です。「35歳定年説」も語られるほどに、プログラマーを続けること自体、報われにくい構造でした。&lt;&#x2F;p&gt;
&lt;p&gt;この差の背景には、産業構造の違いが大きいのではないでしょうか。米国はマイクロソフト社のように自社プロダクトを開発・販売する事業会社が産業の主役で、その成功は株式を通じて開発者個人にも還元されます。一方、日本では事業会社がIT機能を外注する構造になっており、プロダクトの成功を開発者と分け合う仕組みもありません。経営層に技術者出身者が少ないことも、こうした地位の差を生む一因と感じます。&lt;&#x2F;p&gt;
&lt;div class=&quot;booklink-box&quot; style=&quot;text-align:left;padding-bottom:20px;font-size:small;zoom: 1;overflow: hidden;&quot;&gt;&lt;div class=&quot;booklink-image&quot; style=&quot;float:left;margin:0 15px 10px 0;&quot;&gt;&lt;a href=&quot;https:&#x2F;&#x2F;hb.afl.rakuten.co.jp&#x2F;hgc&#x2F;1300574f.7d238558.13005750.4bcd8088&#x2F;yomereba_main_202605120734444595?pc=https%3A%2F%2Fbooks.rakuten.co.jp%2Frb%2F6130084%2F%3Fscid%3Daf_ich_link_urltxt%26m%3Dhttp%3A%2F%2Fm.rakuten.co.jp%2Fev%2Fbook%2F&quot; target=&quot;_blank&quot; &gt;&lt;img src=&quot;https:&#x2F;&#x2F;thumbnail.image.rakuten.co.jp&#x2F;@0_mall&#x2F;book&#x2F;cabinet&#x2F;7577&#x2F;9784822247577.jpg?_ex=200x200&quot; style=&quot;border: none;&quot; &#x2F;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;div&gt;&lt;div class=&quot;booklink-info&quot; style=&quot;line-height:120%;zoom: 1;overflow: hidden;&quot;&gt;&lt;div class=&quot;booklink-name&quot; style=&quot;margin-bottom:10px;line-height:120%&quot;&gt;&lt;a href=&quot;https:&#x2F;&#x2F;hb.afl.rakuten.co.jp&#x2F;hgc&#x2F;1300574f.7d238558.13005750.4bcd8088&#x2F;yomereba_main_202605120734444595?pc=https%3A%2F%2Fbooks.rakuten.co.jp%2Frb%2F6130084%2F%3Fscid%3Daf_ich_link_urltxt%26m%3Dhttp%3A%2F%2Fm.rakuten.co.jp%2Fev%2Fbook%2F&quot; target=&quot;_blank&quot; &gt;闘うプログラマー新装版&lt;&#x2F;a&gt;&lt;div class=&quot;booklink-powered-date&quot; style=&quot;font-size:8pt;margin-top:5px;font-family:verdana;line-height:120%&quot;&gt;posted with &lt;a href=&quot;https:&#x2F;&#x2F;yomereba.com&quot; rel=&quot;nofollow&quot; target=&quot;_blank&quot;&gt;ヨメレバ&lt;&#x2F;a&gt;&lt;&#x2F;div&gt;&lt;&#x2F;div&gt;&lt;div class=&quot;booklink-detail&quot; style=&quot;margin-bottom:5px;&quot;&gt;グレッグ・パスカル・ザカリー&#x2F;山岡洋一 日経BP 2009年07月    &lt;&#x2F;div&gt;&lt;div class=&quot;booklink-link2&quot; style=&quot;margin-top:10px;&quot;&gt;&lt;div class=&quot;shoplinkrakuten&quot; style=&quot;display:inline;margin-right:5px&quot;&gt;&lt;a href=&quot;https:&#x2F;&#x2F;hb.afl.rakuten.co.jp&#x2F;hgc&#x2F;1300574f.7d238558.13005750.4bcd8088&#x2F;yomereba_main_202605120734444595?pc=https%3A%2F%2Fbooks.rakuten.co.jp%2Frb%2F6130084%2F%3Fscid%3Daf_ich_link_urltxt%26m%3Dhttp%3A%2F%2Fm.rakuten.co.jp%2Fev%2Fbook%2F&quot; target=&quot;_blank&quot; &gt;楽天ブックス&lt;&#x2F;a&gt;&lt;&#x2F;div&gt;&lt;div class=&quot;shoplinkamazon&quot; style=&quot;display:inline;margin-right:5px&quot;&gt;&lt;a href=&quot;https:&#x2F;&#x2F;www.amazon.co.jp&#x2F;exec&#x2F;obidos&#x2F;asin&#x2F;4822247570&#x2F;yostosweb-22&#x2F;&quot; target=&quot;_blank&quot; &gt;Amazon&lt;&#x2F;a&gt;&lt;&#x2F;div&gt;&lt;div class=&quot;shoplinkkindle&quot; style=&quot;display:inline;margin-right:5px&quot;&gt;&lt;a href=&quot;https:&#x2F;&#x2F;www.amazon.co.jp&#x2F;gp&#x2F;search?keywords=%E9%97%98%E3%81%86%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9E%E3%83%BC%E6%96%B0%E8%A3%85%E7%89%88&amp;__mk_ja_JP=%83J%83%5E%83J%83i&amp;url=node%3D2275256051&amp;tag=yostosweb-22&quot; target=&quot;_blank&quot; &gt;Kindle&lt;&#x2F;a&gt;&lt;&#x2F;div&gt;                              	  	  	  	  	&lt;&#x2F;div&gt;&lt;&#x2F;div&gt;&lt;div class=&quot;booklink-footer&quot; style=&quot;clear: left&quot;&gt;&lt;&#x2F;div&gt;&lt;&#x2F;div&gt;
</content>
        <summary type="html">伝説のプログラマーDavid Cutlerがマイクロソフト社に移籍し、WindowsNTを生み出すまでの過酷な開発物語。読了して、当時の「OSの時代」や米国でのプログラマーの地位について改めて考えさせられました。
</summary>
        </entry><entry xml:lang="en">
        <title>rcloneとS3ライフサイクルで作る個人データのコールドアーカイブ</title>
        <published>2026-04-30T08:30:42+09:00</published>
        <updated>2026-05-05T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2026/04/rclone/" type="text/html"/>
        <id>https://codedchords.dev/blog/2026/04/rclone/</id>
        
            <content type="html">&lt;!-- textlint-disable --&gt;
&lt;img
  src=&quot;https:&amp;#x2F;&amp;#x2F;codedchords.dev&amp;#x2F;blog&amp;#x2F;2026&amp;#x2F;04&amp;#x2F;rclone&amp;#x2F;cover.webp?h=549d1cce4801beb622f1&quot;
  alt=&quot;Cover&quot; width=&quot;1536&quot; height=&quot;1024&quot; loading=&quot;lazy&quot;
&#x2F;&gt;&lt;!-- textlint-enable --&gt;
&lt;details&gt;
&lt;summary&gt;Table of Contents&lt;&#x2F;summary&gt;
&lt;!-- toc --&gt;
&lt;&#x2F;details&gt;
&lt;p&gt;ドローンで撮りためた動画素材がNASの容量を圧迫してきたので、編集後はほとんど触らないものをAmazon S3に退避させる仕組みを作りました。手元から外しはするものの、まとめ直しのときに見返す可能性は残しておきたい、いわばコールドアーカイブの個人運用版です。&lt;&#x2F;p&gt;
&lt;p&gt;自宅はHome 5Gで上りが20〜30Mbpsと細いため、転送には &lt;code&gt;rclone&lt;&#x2F;code&gt; を使い、回線が太い場所にいるかどうかでパラメータを切り替えながらアップロードしています。さらに保管側はS3のライフサイクルで自動的にGlacier Deep Archiveに降格させ、月額数百円のレンジで運用できるようにしています。&lt;&#x2F;p&gt;
&lt;p&gt;本記事では、この「転送のチューニング」と「保管の自動化」の二段構えを、AWS側の設定からrcloneのオプション、最後にコスト試算まで通しでまとめます。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;なぜAmazon_S3を選んだか&quot;&gt;なぜAmazon S3を選んだか&lt;&#x2F;h2&gt;
&lt;p&gt;「眠らせておく置き場」に求める要件はおおむね以下のとおりです。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;編集後はほとんどアクセスしないが、過去作をまとめ直すときに見返すことはある&lt;&#x2F;li&gt;
&lt;li&gt;手元のストレージやNASから退避させたい、しかし消したくはない&lt;&#x2F;li&gt;
&lt;li&gt;容量が増えても料金がじわじわ膨らまないこと&lt;&#x2F;li&gt;
&lt;li&gt;保管・削除の運用を手動でやらずに済むこと&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;クラウド側の候補としてはDropboxやBoxのようなサブスクリプション型ストレージも挙がりましたが、構造的な違いから最終的にAmazon S3を選びました。観点ごとの比較は以下のとおりです。&lt;&#x2F;p&gt;
&lt;dl&gt;
&lt;dt&gt;料金構造&lt;&#x2F;dt&gt;
&lt;dd&gt;サブスク型は容量プラン単位の月額固定で、使っていない分にも払い続ける必要があります。S3は置いた分・使った分だけの従量課金で、「ほとんど触らないが消したくない」数百GBの素材を保管するだけなら割安に収まります。&lt;&#x2F;dd&gt;
&lt;dt&gt;ストレージクラス&lt;&#x2F;dt&gt;
&lt;dd&gt;サブスク型は内部的にHotストレージのみで、アクセス頻度の低いファイルでも単価は変わりません。S3はStandard &#x2F; Standard-IA &#x2F; Glacier &#x2F; Glacier Deep Archiveと複数階層があり、Deep Archiveまで落とせばStandardより一桁安い単価で保管できます。&lt;&#x2F;dd&gt;
&lt;dt&gt;運用の自動化&lt;&#x2F;dt&gt;
&lt;dd&gt;サブスク型はファイルの整理・移動・削除を手動で行う前提です。S3はライフサイクルで「3日後にDeep Archiveへ降格、2年後に削除」のようなルールを宣言的に書いておけるため、長期保管の管理コストもほぼかかりません。&lt;&#x2F;dd&gt;
&lt;&#x2F;dl&gt;
&lt;p&gt;ひとつだけ運用上の注意点があります。S3にアップロード後すぐにNASから消してしまうと、S3が事実上の唯一コピーになります。バックアップの基本である3-2-1ルール（コピー3、媒体2、オフサイト1）の観点では、編集が完全に終わった素材であっても、NAS側を一定期間（例: 半年〜1年）残しておくと安全側に倒せます。私はNASの容量に余裕がある間は最近のフライトを残し、容量を圧迫してきたら古いものから順にNAS側を整理する運用にしています。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;rcloneとは&quot;&gt;rcloneとは&lt;&#x2F;h2&gt;
&lt;p&gt;S3へのアップロードツールとしては&lt;code&gt;rclone&lt;&#x2F;code&gt;を使用しています。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;code&gt;rclone&lt;&#x2F;code&gt;は70以上のクラウドストレージに対応する汎用ファイル転送ツールです。S3・Google Drive・Dropbox・OneDrive・SFTP・WebDAVなどを統一的なコマンドで扱えます。rsyncのクラウド版というのが一番近い説明です。&lt;&#x2F;p&gt;
&lt;p&gt;これまではMacのGUIアプリ &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;panic.com&#x2F;transmit&#x2F;&quot;&gt;Transmit&lt;&#x2F;a&gt; や、コマンドラインの &lt;code&gt;s3cmd&lt;&#x2F;code&gt; を使っていました。日常的なファイル転送ではどちらも十分でしたが、今回のように回線が細く中断も起こり得る環境で大量にアップロードする用途では、&lt;code&gt;rclone&lt;&#x2F;code&gt; のほうが明確に向いていました。観点ごとの違いは以下のとおりです。&lt;&#x2F;p&gt;
&lt;dl&gt;
&lt;dt&gt;転送のチューニング&lt;&#x2F;dt&gt;
&lt;dd&gt;TransmitはGUIで直感的に扱える一方、並列度やチャンクサイズなどの細かい調整はできません。&lt;code&gt;s3cmd&lt;&#x2F;code&gt; もマルチスレッド転送や帯域制御は限定的です。&lt;code&gt;rclone&lt;&#x2F;code&gt; は並列度・チャンクサイズ・帯域上限・リトライまで細かく指定でき、細い回線でもスループットを引き出せます。&lt;&#x2F;dd&gt;
&lt;dt&gt;不安定な回線への耐性&lt;&#x2F;dt&gt;
&lt;dd&gt;&lt;code&gt;rclone&lt;&#x2F;code&gt; はETagによるチェックサム比較で同一ファイルの再転送をスキップでき、リトライも「ジョブ全体」と「個別HTTPリクエスト」の2階層で設定できます。中断・再開が前提のアーカイブ運用に向いた作りです。&lt;&#x2F;dd&gt;
&lt;dt&gt;対応バックエンドの広さ&lt;&#x2F;dt&gt;
&lt;dd&gt;&lt;code&gt;s3cmd&lt;&#x2F;code&gt; は名前のとおりS3専用です。&lt;code&gt;rclone&lt;&#x2F;code&gt; はS3以外にも多数のクラウドに同じインターフェースで対応するため、将来別のサービスに移行・併用する場合もコマンド体系を変えずに済みます。&lt;&#x2F;dd&gt;
&lt;&#x2F;dl&gt;
&lt;h2 id=&quot;AWS側の設定&quot;&gt;AWS側の設定&lt;&#x2F;h2&gt;
&lt;p&gt;最初にAWS側で必要な準備を済ませておきます。具体的には、転送に使うIAMユーザーの権限と、保管ルールを定義するS3のライフサイクル設定の2点です。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;IAMの権限設定&quot;&gt;IAMの権限設定&lt;&#x2F;h3&gt;
&lt;p&gt;S3バケットへのアクセス権を持つIAMユーザーを作成し、アクセスキーを発行します。ルートアカウントのキーは絶対に使わないでください。最小権限のIAMポリシー例は以下のとおりです（バケット名を &lt;code&gt;video-backup&lt;&#x2F;code&gt; とする場合）。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;json&quot; data-name=&quot;iam-policy.json&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;  &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;Version&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;2012-10-17&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;  &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;Statement&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;: [&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;      &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;Effect&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;Allow&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;      &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;Action&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;: [&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;s3:ListBucket&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;s3:GetBucketLocation&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;],&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;      &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;Resource&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;arn:aws:s3:::video-backup&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    },&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;      &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;Effect&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;Allow&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;      &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;Action&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;: [&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;        &amp;quot;s3:PutObject&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;        &amp;quot;s3:GetObject&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;        &amp;quot;s3:DeleteObject&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;        &amp;quot;s3:AbortMultipartUpload&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;        &amp;quot;s3:ListMultipartUploadParts&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;      ],&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;      &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;Resource&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;arn:aws:s3:::video-backup&#x2F;*&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;  ]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;code&gt;s3:AbortMultipartUpload&lt;&#x2F;code&gt; はマルチパートアップロード失敗時のクリーンアップに必要です。これがないと中断したアップロードの残骸が課金対象として残り続けてしまいます。&lt;&#x2F;p&gt;
&lt;p&gt;ここまでの内容をAWS CLIで適用する手順は以下のとおりです。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# IAM ユーザーを作成&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;aws&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; iam create-user --user-name rclone-backup&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# 上記の iam-policy.json からポリシーを作成&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;aws&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; iam create-policy&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;  --policy-name VideoBackupPolicy&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;  --policy-document file:&#x2F;&#x2F;iam-policy.json&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# ユーザーにポリシーをアタッチ&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;ACCOUNT_ID&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;$(&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;aws&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; sts get-caller-identity --query Account --output text&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;aws&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; iam attach-user-policy&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;  --user-name rclone-backup&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;  --policy-arn arn:aws:iam::&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-source&quot;&gt;${ACCOUNT_ID}&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;:policy&#x2F;VideoBackupPolicy&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# アクセスキーを発行（SecretAccessKey は一度しか表示されないので保管すること）&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;aws&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; iam create-access-key --user-name rclone-backup&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;最後のコマンドで返ってきた &lt;code&gt;AccessKeyId&lt;&#x2F;code&gt; と &lt;code&gt;SecretAccessKey&lt;&#x2F;code&gt; は、後段の &lt;code&gt;rclone config&lt;&#x2F;code&gt; でそのまま使います。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;S3ライフサイクルルール&quot;&gt;S3ライフサイクルルール&lt;&#x2F;h3&gt;
&lt;p&gt;長期アーカイブ用途では、ストレージクラスを段階的に下げて保管料を抑えたり、中断したマルチパートアップロードの残骸を自動で掃除するルールを入れておくと、安全かつ低コストで運用できます。以下は2つのルールを1ファイルで設定する例です。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;ルール1: アップロード後3日経過したオブジェクトをGlacier Deep Archiveに移し、2年（730日）後に削除する&lt;&#x2F;li&gt;
&lt;li&gt;ルール2: 7日以上完了していないマルチパートアップロードを中止してパートを削除する&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;&lt;code&gt;lifecycle.json&lt;&#x2F;code&gt; を用意します。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;json&quot; data-name=&quot;lifecycle.json&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;  &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;Rules&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;: [&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;      &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;ID&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;ArchiveAfter3DaysExpireAfter2Years&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;      &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;Status&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;Enabled&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;      &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;Filter&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;: {},&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;      &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;Transitions&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;: [&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;        {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;          &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;Days&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 3&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;          &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;StorageClass&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;DEEP_ARCHIVE&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;        }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;      ],&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;      &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;Expiration&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;: {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;        &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;Days&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 730&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;      }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    },&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;      &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;ID&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;AbortIncompleteMultipartUploadAfter7Days&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;      &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;Status&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;Enabled&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;      &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;Filter&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;: {},&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;      &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;AbortIncompleteMultipartUpload&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;: {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;        &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;DaysAfterInitiation&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 7&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;      }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;  ]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;バケットに適用します。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;aws&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; s3api put-bucket-lifecycle-configuration&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;  --bucket video-backup&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;  --lifecycle-configuration file:&#x2F;&#x2F;lifecycle.json&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;現在の設定を確認します。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;aws&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; s3api get-bucket-lifecycle-configuration --bucket video-backup&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;設定にあたっての注意点は以下のとおりです。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Filter: {}&lt;&#x2F;code&gt; はバケット全体が対象という意味。プレフィックスで絞るなら &lt;code&gt;&quot;Filter&quot;: {&quot;Prefix&quot;: &quot;video&#x2F;&quot;}&lt;&#x2F;code&gt; のように書く&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;Days&lt;&#x2F;code&gt; はオブジェクトの作成日からの経過日数。ライフサイクルの判定はUTCの00:00に1日1回走るため、設定した翌日にすぐ動くわけではない&lt;&#x2F;li&gt;
&lt;li&gt;Glacier Deep Archiveは最安だが、復元に最大48時間（Bulkなら数時間）かかる。「もう見ない可能性が高いがゼロではない」素材向き&lt;&#x2F;li&gt;
&lt;li&gt;Deep Archiveは最低保管期間が180日。180日未満で削除や移動をすると残り日数分の料金が発生する。今回は作成3日後に移して2年後（DAに約720日滞在）に削除するため、最低保管期間は十分満たす&lt;&#x2F;li&gt;
&lt;li&gt;128KB未満の小さいオブジェクトはDeep Archiveへの移行対象外（移行してもStandardに留まる）。動画用途なら気にしなくて構わないが、混在バケットでは留意しておく&lt;&#x2F;li&gt;
&lt;li&gt;マルチパートアップロード残骸の削除ルールは、IAMポリシーの &lt;code&gt;s3:AbortMultipartUpload&lt;&#x2F;code&gt; とは別に必要。IAMはクライアント側が中止する権限、ライフサイクルはS3側が自動で中止してくれる仕組みなので、両方そろえておくのが望ましい状態&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;rcloneのインストールと設定&quot;&gt;rcloneのインストールと設定&lt;&#x2F;h2&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;brew&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; install rclone&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;リモートの設定は &lt;code&gt;rclone config&lt;&#x2F;code&gt; を起動して対話的に進めます。新規リモート作成時に入力していく項目を抜粋すると以下のとおりです（&lt;code&gt;&amp;gt;&lt;&#x2F;code&gt; の左がプロンプト、右が入力値）。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; rclone config&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;n&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;) New remote&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;name&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; s3-aws&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;Storage&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; s3&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;provider&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; AWS&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;env_auth&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language z-false&quot;&gt; false&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;access_key_id&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; AKIA...&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;secret_access_key&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; ...&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;region&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; ap-northeast-1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;endpoint&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;     （空欄でOK）&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;location_constraint&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; ap-northeast-1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;acl&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; private&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;storage_class&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; STANDARD&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;設定ファイルは &lt;code&gt;~&#x2F;.config&#x2F;rclone&#x2F;rclone.conf&lt;&#x2F;code&gt; に&lt;strong&gt;平文&lt;&#x2F;strong&gt;で保存されます。共用マシンでは取り扱いに注意してください。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;rcloneの推奨パラメータ&quot;&gt;rcloneの推奨パラメータ&lt;&#x2F;h2&gt;
&lt;p&gt;自宅のHome 5G（上り20〜30Mbps）想定での起動例は以下のとおりです。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;rclone&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; copy .&#x2F;video&#x2F; s3-aws:video-backup&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;  --transfers&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 2&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;  --s3-chunk-size 64M&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;  --s3-upload-concurrency&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 4&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;  --s3-no-check-bucket&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;  --checksum&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;  --progress&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;  --retries&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 10&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;  --low-level-retries&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 20&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;  --log-file=rclone-&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;$(&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;date&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; +%Y%m%d-%H%M%S&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;.log&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;  --log-level INFO&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;S3では1ファイル内の並列度は &lt;code&gt;--s3-upload-concurrency&lt;&#x2F;code&gt; が直接コントロールするため、&lt;code&gt;--multi-thread-streams&lt;&#x2F;code&gt; は併用しません。両方指定しても効果が二重に効くわけではなく、メモリ使用量だけが増えてしまうので、&lt;strong&gt;S3 バックエンドでは &lt;code&gt;--s3-upload-concurrency&lt;&#x2F;code&gt; に一本化&lt;&#x2F;strong&gt; します。回線が太い環境（オフィス・コワーキングスペース等で上り100Mbps以上）では &lt;code&gt;--transfers 4&lt;&#x2F;code&gt; まで増やしても問題ありません。&lt;&#x2F;p&gt;
&lt;p&gt;各オプションの意味と推奨値は以下のとおりです。&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;オプション&lt;&#x2F;th&gt;&lt;th&gt;推奨値&lt;&#x2F;th&gt;&lt;th&gt;説明&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;--transfers&lt;&#x2F;td&gt;&lt;td&gt;1〜2（細回線）&#x2F; 4（太回線）&lt;&#x2F;td&gt;&lt;td&gt;同時に転送するファイル数。Home 5G のような上り20〜30Mbps の環境では 1〜2 のほうがファイルの完了が早く、リトライ時の損失も小さい&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;--s3-chunk-size&lt;&#x2F;td&gt;&lt;td&gt;64M&lt;&#x2F;td&gt;&lt;td&gt;マルチパートアップロードの1パートのサイズ。デフォルト 5M を動画用途では 64M〜128M に。メモリ使用量が &lt;code&gt;chunk_size × upload_concurrency × transfers&lt;&#x2F;code&gt; で増える点に注意&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;--s3-upload-concurrency&lt;&#x2F;td&gt;&lt;td&gt;4&lt;&#x2F;td&gt;&lt;td&gt;1ファイル内で同時にアップロードするパート数&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;--s3-no-check-bucket&lt;&#x2F;td&gt;&lt;td&gt;有効&lt;&#x2F;td&gt;&lt;td&gt;バケット存在チェックをスキップ。最小権限 IAM ではデフォルトのままだと起動時のチェックがエラーになることがある&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;--checksum&lt;&#x2F;td&gt;&lt;td&gt;有効&lt;&#x2F;td&gt;&lt;td&gt;ETag 比較で同一ファイルの再転送をスキップ。サイズと更新時刻だけのデフォルトより確実&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;--retries&lt;&#x2F;td&gt;&lt;td&gt;10&lt;&#x2F;td&gt;&lt;td&gt;ジョブ全体のリトライ回数&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;--low-level-retries&lt;&#x2F;td&gt;&lt;td&gt;20&lt;&#x2F;td&gt;&lt;td&gt;個別 HTTP リクエストのリトライ回数&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;--progress (-P)&lt;&#x2F;td&gt;&lt;td&gt;有効&lt;&#x2F;td&gt;&lt;td&gt;リアルタイムで進捗を表示&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;--log-file&lt;&#x2F;td&gt;&lt;td&gt;&lt;code&gt;rclone-$(date +%Y%m%d-%H%M%S).log&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;ログをファイルに残しておくとエラー追跡や再開判断に役立つ&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;--log-level&lt;&#x2F;td&gt;&lt;td&gt;&lt;code&gt;INFO&lt;&#x2F;code&gt;（デバッグ時 &lt;code&gt;DEBUG&lt;&#x2F;code&gt;）&lt;&#x2F;td&gt;&lt;td&gt;ログレベル&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;--bwlimit&lt;&#x2F;td&gt;&lt;td&gt;状況に応じて&lt;&#x2F;td&gt;&lt;td&gt;上限を制限（例: &lt;code&gt;10M&lt;&#x2F;code&gt;）。&lt;code&gt;--bwlimit &quot;08:00,512k 18:00,off&quot;&lt;&#x2F;code&gt; のように時刻指定で時間帯ごとに切り替えも可能&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;ライフサイクルでDeep Archiveに降格したオブジェクトに対して、&lt;code&gt;rclone copy&lt;&#x2F;code&gt; で同名ファイルを再アップロードしようとすると、内部で実行されるGET（既存ファイルとのチェックサム比較）がDeep Archiveオブジェクトに対しては失敗します。同じパスに同名ファイルを再投入する用途がある場合は、&lt;code&gt;--immutable&lt;&#x2F;code&gt;（同名ファイルが既に存在したら転送をスキップしてエラーにしない）か &lt;code&gt;--no-traverse&lt;&#x2F;code&gt;（既存ファイルとの比較をしない）を併用するか、そもそも保存先のキー命名でタイムスタンプを含めて衝突を避けます。今回の動画アーカイブのようにファイル名がフライト日時で一意な場合は、特別な対策は不要です。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;macで中断させない方法&quot;&gt;macで中断させない方法&lt;&#x2F;h2&gt;
&lt;p&gt;長時間の転送中にmacOSがスリープに入ると転送が止まります。&lt;code&gt;caffeinate&lt;&#x2F;code&gt; を使ってシステムスリープを抑止しながら実行します。&lt;&#x2F;p&gt;
&lt;!-- textlint-disable --&gt;
&lt;aside data-position=&quot;right&quot;&gt;
    &lt;p&gt;&lt;code&gt;caffeinate&lt;&#x2F;code&gt; は macOS に標準で含まれるコマンドです。&lt;&#x2F;p&gt;

&lt;&#x2F;aside&gt;
&lt;!-- textlint-enable --&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;caffeinate&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; -i rclone copy .&#x2F;video&#x2F; s3-aws:video-backup&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;  --transfers&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 4&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;  --s3-chunk-size 64M&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;  --s3-upload-concurrency&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 4&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;  --s3-no-check-bucket&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;  --checksum&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;  --progress&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;  --retries&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 10&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;  --low-level-retries&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 20&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;  --log-file=rclone-&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;$(&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;date&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; +%Y%m%d-%H%M%S&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;.log&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;  --log-level INFO&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;主なオプションは以下のとおりです。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;-i&lt;&#x2F;code&gt; システムのアイドルスリープを防止（プロセスが終わるまで有効）&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;-d&lt;&#x2F;code&gt; ディスプレイのスリープも防止（不要なら省略）&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;-s&lt;&#x2F;code&gt; AC電源接続時のみスリープ防止&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;-u -t 3600&lt;&#x2F;code&gt; 指定秒数だけスリープ防止（プロセスを伴わない用途）&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;&lt;code&gt;caffeinate&lt;&#x2F;code&gt; を前置すると、そのコマンドが終了するまで自動でスリープ抑止が解除されます。バックグラウンドで動かす場合は &lt;code&gt;nohup caffeinate -i rclone copy ... &amp;amp;&lt;&#x2F;code&gt; のようにすれば、ターミナルを閉じても継続します（ログは &lt;code&gt;--log-file&lt;&#x2F;code&gt; に必ず残しておきます）。&lt;&#x2F;p&gt;
&lt;p&gt;蓋を閉じてもスリープさせたくない場合は &lt;code&gt;caffeinate&lt;&#x2F;code&gt; だけでは不十分なことがあるので、事前に以下を実行しておくか、別途 &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;apps.apple.com&#x2F;app&#x2F;amphetamine&#x2F;id937984704&quot;&gt;Amphetamine&lt;&#x2F;a&gt; のようなツールを使うのが確実です。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;sudo&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; pmset -a disablesleep&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 1&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;   # 蓋を閉じてもスリープしない（作業後は0に戻す）&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;認証情報の管理を1Password_CLIに移す（2026-05-05更新）&quot;&gt;認証情報の管理を1Password CLIに移す（2026-05-05更新）&lt;&#x2F;h2&gt;
&lt;p&gt;ここまでの設定では &lt;code&gt;~&#x2F;.config&#x2F;rclone&#x2F;rclone.conf&lt;&#x2F;code&gt; にAWSのアクセスキーが平文で残ります。dotfilesで同期したり共用マシンに置く運用では避けたいので、認証情報を &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;developer.1password.com&#x2F;docs&#x2F;cli&#x2F;&quot;&gt;1Password CLI&lt;&#x2F;a&gt; (&lt;code&gt;op&lt;&#x2F;code&gt;) に移し、&lt;code&gt;op run&lt;&#x2F;code&gt; で実行時に環境変数として注入する構成も用意しました。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;code&gt;rclone.conf&lt;&#x2F;code&gt; 側はキーを書かず、&lt;code&gt;env_auth = true&lt;&#x2F;code&gt; にしてAWS標準の認証情報チェーン（環境変数→&lt;code&gt;~&#x2F;.aws&#x2F;credentials&lt;&#x2F;code&gt;→IAMロール）から都度取得する動作に変えます。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;ini&quot; data-name=&quot;~&#x2F;.config&#x2F;rclone&#x2F;rclone.conf&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-section z-group-title z-ini&quot;&gt;s3-aws&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-other z-definition z-ini&quot;&gt;type&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; s3&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-other z-definition z-ini&quot;&gt;provider&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; AWS&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-other z-definition z-ini&quot;&gt;env_auth&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; true&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-other z-definition z-ini&quot;&gt;region&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; ap-northeast-1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-other z-definition z-ini&quot;&gt;location_constraint&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; ap-northeast-1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-other z-definition z-ini&quot;&gt;acl&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; private&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-other z-definition z-ini&quot;&gt;storage_class&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; STANDARD&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;発行済みのキーは1Passwordに保管します。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;op&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt; item create --category=&amp;quot;API Credential&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;  --vault=Private&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt;  --title=&amp;quot;rclone-backup-aws&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt;  username=&amp;quot;AKIA...&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt;  credential=&amp;quot;...&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;参照用のenvテンプレートを &lt;code&gt;~&#x2F;.config&#x2F;rclone&#x2F;s3-backup.env&lt;&#x2F;code&gt; として配置します。&lt;code&gt;rclone.conf&lt;&#x2F;code&gt; と同じディレクトリで管理でき、値ではなく &lt;code&gt;op:&#x2F;&#x2F;...&lt;&#x2F;code&gt; の参照しか書かれないため、dotfilesに含めて同期しても問題ありません。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot; data-name=&quot;~&#x2F;.config&#x2F;rclone&#x2F;s3-backup.env&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;AWS_ACCESS_KEY_ID&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;op:&#x2F;&#x2F;Private&#x2F;rclone-backup-aws&#x2F;username&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;AWS_SECRET_ACCESS_KEY&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;op:&#x2F;&#x2F;Private&#x2F;rclone-backup-aws&#x2F;credential&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;実行時は &lt;code&gt;op run --env-file&lt;&#x2F;code&gt; でラップし、&lt;code&gt;op&lt;&#x2F;code&gt; が1Passwordから値を取り出して環境変数として注入します。先述の起動例は以下のように書き換わります。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;op&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt; run --env-file=&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-normal z-shell&quot;&gt;$HOME&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt;&#x2F;.config&#x2F;rclone&#x2F;s3-backup.env&amp;quot; -- rclone copy .&#x2F;video&#x2F; s3-aws:video-backup&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;  --transfers&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 2&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;  --s3-chunk-size 64M&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;  --s3-upload-concurrency&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 4&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;  --s3-no-check-bucket&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;  --checksum&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;  --progress&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;  --retries&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 10&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;  --low-level-retries&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 20&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;  --log-file=rclone-&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;$(&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;date&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; +%Y%m%d-%H%M%S&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;.log&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;  --log-level INFO&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;code&gt;caffeinate&lt;&#x2F;code&gt; と組み合わせる場合は、&lt;code&gt;caffeinate&lt;&#x2F;code&gt; を最外殻に置きます。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;caffeinate&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt; -i op run --env-file=&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-normal z-shell&quot;&gt;$HOME&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt;&#x2F;.config&#x2F;rclone&#x2F;s3-backup.env&amp;quot; -- rclone copy .&#x2F;video&#x2F; s3-aws:video-backup&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;  --transfers&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 4&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;  --s3-chunk-size 64M&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;  --s3-upload-concurrency&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 4&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;  --s3-no-check-bucket&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;  --checksum&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;  --progress&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;  --retries&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 10&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;  --low-level-retries&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 20&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;  --log-file=rclone-&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;$(&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;date&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; +%Y%m%d-%H%M%S&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;.log&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;  --log-level INFO&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;まとめ&quot;&gt;まとめ&lt;&#x2F;h2&gt;
&lt;p&gt;rcloneのチューニングとS3のライフサイクルを組み合わせて、個人データのコールドアーカイブを構築する構成をまとめました。回線の細さに左右されず転送を完了させ、長期保管のコストはストレージクラスの自動降格で抑える、という二段構えです。&lt;&#x2F;p&gt;
&lt;p&gt;参考として、私の運用パターン（月3フライト × 1回20GB = 月60GB）で運用した場合の年度ごとの料金見積もりは以下のようになります。3日後にGlacier Deep Archiveへ降格、2年で削除するライフサイクルを前提としています。NASにローカルコピーを保持しているため、S3のStandard滞在は最小限に切り詰めています。&lt;&#x2F;p&gt;
&lt;!-- textlint-disable --&gt;
&lt;aside data-position=&quot;right&quot;&gt;
    &lt;p&gt;左記は保管料のみ。取り出す場合には別途料金が発生します。&lt;&#x2F;p&gt;

&lt;&#x2F;aside&gt;


&lt;noscript&gt;
    &lt;strong&gt;⚠️ JavaScript is required to render the diagram.&lt;&#x2F;strong&gt;
&lt;&#x2F;noscript&gt;
&lt;pre class=&quot;mermaid invertible-image&quot;&gt;
    xychart-beta
title &quot;年度ごとのS3保管料金（千円）&quot;
x-axis [&quot;1年目&quot;, &quot;2年目&quot;, &quot;3年目&quot;, &quot;4年目&quot;, &quot;5年目&quot;]
y-axis &quot;料金（千円）&quot; 0 --&gt; 7
bar [1.6, 4.2, 5.5, 5.5, 5.5]
&lt;&#x2F;pre&gt;
&lt;!-- textlint-enable --&gt;
&lt;p&gt;1〜2年目はDeep Archive側に毎年720GBずつ積み上がるため線形に増加し、3年目以降は毎月のアップロード分と削除分が釣り合って定常状態に入り、年額 ¥5,500程度・累積保管量約1.5TBで頭打ちになります。月額換算すると ¥460程度で、Standard滞在を3日に切り詰めることで、料金のほぼ全てがDeep Archiveの単価で支配される構成です。料金は1ドル=¥150換算、AWSの公開価格（ap-northeast-1、執筆時点）に基づく概算なので、実費は為替・価格改定・取り出し料金で変動します。&lt;&#x2F;p&gt;
&lt;p&gt;この設計の枠組みは、データ特性に合わせて他の用途にも応用できます。私は同じS3アカウントでLogic Proの楽曲プロジェクト（月4曲、1曲500MB）も管理しており、こちらは「再編集の可能性が長く残る」という性質に合わせて、Standard滞在を1年・削除を10年に設定しています。&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;用途&lt;&#x2F;th&gt;&lt;th&gt;月次&lt;&#x2F;th&gt;&lt;th&gt;Std→DA&lt;&#x2F;th&gt;&lt;th&gt;削除&lt;&#x2F;th&gt;&lt;th&gt;定常年額&lt;&#x2F;th&gt;&lt;th&gt;定常容量&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;ドローン動画&lt;&#x2F;td&gt;&lt;td&gt;60 GB&lt;&#x2F;td&gt;&lt;td&gt;3日&lt;&#x2F;td&gt;&lt;td&gt;2年&lt;&#x2F;td&gt;&lt;td&gt;¥5,500&lt;&#x2F;td&gt;&lt;td&gt;1.5 TB&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;楽曲プロジェクト&lt;&#x2F;td&gt;&lt;td&gt;2 GB&lt;&#x2F;td&gt;&lt;td&gt;1年&lt;&#x2F;td&gt;&lt;td&gt;10年&lt;&#x2F;td&gt;&lt;td&gt;¥1,900&lt;&#x2F;td&gt;&lt;td&gt;240 GB&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;両方合算しても月額 ¥620程度、合計約1.7TBです。データの性格に応じてライフサイクルを分ければ、同じ仕組みで複数の用途を最適化できます。&lt;&#x2F;p&gt;
</content>
        <summary type="html">ドローンの動画素材やLogic Proの楽曲データなど、編集後はほとんど触らないが消したくないデータの「眠らせ場所」を、Amazon S3とrcloneで構築した記録です。細回線でも止まらない転送のチューニングから、Glacier Deep Archiveを使った長期保管のコスト設計まで、二段構えでまとめました。
</summary>
        </entry><entry xml:lang="en">
        <title>Cloudflare Agents Week 2026が告げるCloud 2.0時代: エンタープライズの主戦場が移る</title>
        <published>2026-04-27T07:00:13+09:00</published>
        <updated>2026-04-27T07:00:13+09:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2026/04/cloud2-0/" type="text/html"/>
        <id>https://codedchords.dev/blog/2026/04/cloud2-0/</id>
        
            <content type="html">&lt;!-- textlint-disable --&gt;
&lt;img
  src=&quot;https:&amp;#x2F;&amp;#x2F;codedchords.dev&amp;#x2F;blog&amp;#x2F;2026&amp;#x2F;04&amp;#x2F;cloud2-0&amp;#x2F;cover.webp?h=aa99350328ab1f917f77&quot;
  alt=&quot;Cover&quot; width=&quot;1536&quot; height=&quot;1024&quot; loading=&quot;lazy&quot;
&#x2F;&gt;&lt;!-- textlint-enable --&gt;
&lt;p&gt;Cloudflareは2026年4月13日〜17日に「Agents Week 2026」を開催して、10個以上の新機能を一気に発表しました。新機能の多くが、LLMエージェント(Claude Codeのような「目的を与えられたら、自律的に考え道具を使いタスクを完遂するLLMを使った仕組み」)に関連したものです。&lt;&#x2F;p&gt;
&lt;p&gt;Cloudflareがエージェント向けプラットフォームのロードマップを一気に開示しきった印象的な5日間でした。&lt;&#x2F;p&gt;
&lt;details&gt;
&lt;summary&gt;Table of Contents&lt;&#x2F;summary&gt;
&lt;!-- toc --&gt;
&lt;&#x2F;details&gt;
&lt;h2 id=&quot;Cloud_2.0の時代&quot;&gt;Cloud 2.0の時代&lt;&#x2F;h2&gt;
&lt;p&gt;今回の発表をまとめて眺めると、Cloudの変遷は次のように整理できます。「Cloud x.0」という言い回しが使い古されているのは承知の上で、それでも今回の地殻変動を端的に表すのに「Cloud 2.0」はちょうど良い言葉だと感じています。&lt;&#x2F;p&gt;
&lt;!-- textlint-disable --&gt;
&lt;aside data-position=&quot;right&quot;&gt;
    &lt;p&gt;本記事における「Cloud 2.0」の定義: LLMエージェントがCloudのワークロードの主役となる新しいレイヤーを指す、本記事独自の用語として用います。過去に同じ表記が別の意味で使われてきた経緯がありますが、本記事の主張とは無関係です。&lt;&#x2F;p&gt;

&lt;&#x2F;aside&gt;
&lt;!-- textlint-enable --&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th style=&quot;text-align: left&quot;&gt;世代&lt;&#x2F;th&gt;&lt;th style=&quot;text-align: left&quot;&gt;呼称&lt;&#x2F;th&gt;&lt;th style=&quot;text-align: left&quot;&gt;本質的な役割&lt;&#x2F;th&gt;&lt;th style=&quot;text-align: left&quot;&gt;操作主体 (Who)&lt;&#x2F;th&gt;&lt;th style=&quot;text-align: left&quot;&gt;主な関心事・技術&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;&lt;strong&gt;Cloud 0.5&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;&lt;strong&gt;仮想化インフラ&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;&lt;strong&gt;「場所」の移動&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;インフラ担当者 (手動)&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;リフト＆シフト、VM、データセンターの仮想化&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;&lt;strong&gt;Cloud 1.0&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;&lt;strong&gt;Cloud Native&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;&lt;strong&gt;「構造」の最適化&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;開発者 (コード&#x2F;API)&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;マネージドサービス、K8s、サーバレス、IaC&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;&lt;strong&gt;Cloud 2.0&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;&lt;strong&gt;Agentic Cloud&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;&lt;strong&gt;「意思」の自律化&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;&lt;strong&gt;AIエージェント&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;自律的な推論、長期記憶、Tool Use、動的リソース制御&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;3つの世代を「場所→構造→意思」の流れで並べると、世代が進むごとに操作主体が一段上のレイヤーへ移っていくことが見えてきます。Cloud 0.5でインフラ担当者がVMを操作し、Cloud 1.0で開発者がAPIやIaC越しにマネージドサービスを操作してきたところに、Cloud 2.0ではLLMエージェント自身がインフラを叩く側に立ちます。今のエンタープライズが向き合っているのは、「LLMエージェントをいかに効率よく稼働させるか」を中心に据えた新しいITインフラストラクチャーの設計です。&lt;&#x2F;p&gt;
&lt;p&gt;ひとつ前提を強調しておきます。Cloud 2.0はCloud 1.0を置き換えるものではありません。銀行の勘定系、ECのバックエンド、SaaSの基盤といった既存のワークロードは、引き続きCloud 1.0のプリミティブの上で動き続けます。Cloud 2.0はその上に積み上がる新しいレイヤーとして立ち上がり、エージェントが必要に応じて下のCloud 1.0のアプリを呼び出すこともある、という関係です。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;LLMエージェントとは&quot;&gt;LLMエージェントとは&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;strong&gt;LLMエージェントとは、目的を与えられたら自分で考え道具を使いタスクを完遂するLLMを用いた仕組み&lt;&#x2F;strong&gt;です。聞かれたことに答えるだけのチャットボットと違い、ゴールに向かって自分で手を動かしていきます。具体的にはAnthropicのClaude CodeやClaude Coworkのようなサービスです。&lt;&#x2F;p&gt;
&lt;p&gt;より正確に整理すると、エージェントは主に以下の4つの要素で構成されるシステムと定義されることが多いです。&lt;&#x2F;p&gt;
&lt;dl&gt;
&lt;dt&gt;脳 (Brain &#x2F; Planning)&lt;&#x2F;dt&gt;
&lt;dd&gt;LLM本体です。与えられた大きな目標を、実行可能な小さなステップ(サブタスク)に分解します。過去の失敗から学び、計画を修正する能力もここに含まれます。&lt;&#x2F;dd&gt;
&lt;dt&gt;記憶 (Memory)&lt;&#x2F;dt&gt;
&lt;dd&gt;会話の文脈や現在の作業手順を保持する短期記憶と、外部データベース(RAGなど)を活用して膨大な情報を必要に応じて取り出す長期記憶の二段構えです。&lt;&#x2F;dd&gt;
&lt;dt&gt;道具の使用 (Tool Use &#x2F; Action)&lt;&#x2F;dt&gt;
&lt;dd&gt;エージェントの大きな特徴です。LLMはテキストを生成するだけでなく、Web検索で最新情報を取得し、コード実行で計算やデータ分析を行ない、API連携でメール送信・カレンダー予約・ファイル操作といった外部ツールを呼び出します。&lt;&#x2F;dd&gt;
&lt;dt&gt;認識と判断 (Perception &amp; Reflection)&lt;&#x2F;dt&gt;
&lt;dd&gt;実行した結果が正しかったか、目標に近づいているかを自己評価し、次の行動を決定します。&lt;&#x2F;dd&gt;
&lt;&#x2F;dl&gt;
&lt;p&gt;この4要素は、計画→実行→評価のループを回しながら、共通の記憶を参照・更新する形で連動します。&lt;&#x2F;p&gt;
&lt;p&gt;ChatGPTをはじめとするLLMが登場したとき、企業はいかにこれを業務システム(アプリケーション)に取り込むかを検討しました。RAGによる社内ナレッジ検索、お問い合わせの自動応答、議事録の要約など、LLMをアプリケーションの中の一機能として組み込む方向です。&lt;&#x2F;p&gt;
&lt;p&gt;しかしその方向での検討は正しい解ではありませんでした。LLMがアプリケーションを含めたさまざまな道具を使い、人間に成り代わって判断しながら業務を行なう。そういう世界が見えてきたのです。LLMを部品として埋め込む構図から、LLMが部品を使う側に立つ構図への反転です。&lt;&#x2F;p&gt;
&lt;p&gt;この転換の背景には、Anthropicが2024年11月に公開したMCP (Model Context Protocol) で得られた「LLMを外と繋げば爆発的に生産性が上がる」という体験があります。Claude Codeはこの延長線上で、もっとカジュアルにLLMに外の道具を使わせればMCPより更に効果的であるということを実証してみせました。&lt;&#x2F;p&gt;
&lt;p&gt;つまり、既存の業務システムは無くなりません。LLMエージェントから利用される対象になります。アプリケーションは引き続きそこに存在しますが、操作する主体が人間からエージェントに移る、という関係です。前節の表で操作主体をAIエージェントに置いたのは、まさにこの転換を指しています。&lt;&#x2F;p&gt;
&lt;p&gt;使われ方の面でも構造が変わります。Cloud 1.0までのアプリケーションは「1つのアプリが多数のユーザを捌く」one-to-manyの前提で設計されてきました。コードは共通で、水平スケールでスループットを上げ、コストはユーザ数に対してサブリニアに伸びる構造です。エージェントはこれを反転させ、1ユーザ(あるいは1タスク)に対して専用の実行環境を割り当てるone-to-oneのモデルになります。&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th style=&quot;text-align: left&quot;&gt;軸&lt;&#x2F;th&gt;&lt;th style=&quot;text-align: left&quot;&gt;Cloud 1.0 アプリ&lt;&#x2F;th&gt;&lt;th style=&quot;text-align: left&quot;&gt;LLMエージェント&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;実行モデル&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;one-to-many&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;one-to-one&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;実行環境&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;ユーザ間で共有&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;ユーザごとに専用&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;コスト構造&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;サブリニア&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;ほぼリニア&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;この「1ユーザに専用環境」という前提が、次節で見るインフラ要件の起点になります。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;Cloud_2.0で必要なインフラ機能&quot;&gt;Cloud 2.0で必要なインフラ機能&lt;&#x2F;h2&gt;
&lt;p&gt;前節で整理したLLMエージェントの4要素と、ユーザ1人に1つの実行環境を割り当てるone-to-oneのモデル。この2つを起点にすると、Cloud 2.0レイヤーが要求するインフラ機能は素直に導けます。&lt;&#x2F;p&gt;
&lt;p&gt;エージェントが実行時に取る活動を一段ずつ分解していくと、それぞれに対応するインフラ機能が見えてきます。&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th style=&quot;text-align: left&quot;&gt;エージェントの活動&lt;&#x2F;th&gt;&lt;th style=&quot;text-align: left&quot;&gt;求められるインフラ機能&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;LLMの推論を回し続ける(脳・認識)&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;複数モデルを切り替えられる統合推論レイヤー&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;AIが書いたコードを安全に走らせる(道具)&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;ミリ秒で立ち上がる軽量実行環境&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;長尺タスクやコーディング作業を進める(道具)&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;永続的なフル機能Linux環境&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;社内DBや業務APIに到達する(道具)&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;エージェント単位のプライベートネットワーク&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;Webアプリを操作する(道具)&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;マネージドなブラウザ自動化&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;大量のコードを生成・分岐・統合する(道具)&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;Git互換の版管理ストレージ&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;状態と過去のやり取りを保持する(記憶)&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;コンテキスト外で保持できる永続記憶レイヤー&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;ここで効いてくるのがone-to-oneのモデルです。1ユーザに1つの専用実行環境を割り当てるため、表に並べた各機能は「同時に大量に立ち上げ、短時間で捨てる」パターンに耐える必要があります。Cloudflareがブログ「&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;blog.cloudflare.com&#x2F;welcome-to-agents-week&#x2F;&quot;&gt;Welcome to Agents Week&lt;&#x2F;a&gt;」で示した試算が分かりやすい例です。米国だけで1億人を超えるナレッジワーカーがそれぞれ数個のエージェントを15%の同時実行率で動かすと、同時セッション数は約2400万、CPU 1基あたり25〜50ユーザを想定すると米国分だけで50万〜100万CPU相当の容量が必要になる、という見積もりです。one-to-many前提の最適化のままでは、この規模には到底届きません。&lt;&#x2F;p&gt;
&lt;p&gt;つまりCloud 2.0レイヤーで必要なのは、上の表に並べたプリミティブを、one-to-oneでも破綻しないコスト構造で提供できるインフラです。次節では、このレイヤーで誰がどう動いているかを見ていきます。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;Cloud_2.0で変わる力関係&quot;&gt;Cloud 2.0で変わる力関係&lt;&#x2F;h2&gt;
&lt;p&gt;CloudflareはAgents Week 2026の発表で、前節で挙げたCloud 2.0要件のすべてに対応するサービスを揃えました。&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th style=&quot;text-align: left&quot;&gt;要件(前節の表)&lt;&#x2F;th&gt;&lt;th style=&quot;text-align: left&quot;&gt;Cloudflareサービス&lt;&#x2F;th&gt;&lt;th style=&quot;text-align: left&quot;&gt;Agents Weekでの発表&lt;&#x2F;th&gt;&lt;th style=&quot;text-align: left&quot;&gt;説明&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;統合推論レイヤー&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;AI Gateway&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;○&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;拡張(14社・70モデル、Workers AIバインディング追加)&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;軽量実行環境&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;Dynamic Workers&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;○&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;今回発表の目玉。2026年3月24日に有料ユーザーへopen beta開放&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;永続Linux環境&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;Sandboxes&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;○&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;GA昇格(active CPU pricing、Outbound Workers等を追加)&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;エージェント単位プライベートネットワーク&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;Cloudflare Mesh&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;○&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;新規発表&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;ブラウザ自動化&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;Browser Run&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;○&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;旧Browser Renderingを改名。Live View等を追加&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;版管理ストレージ&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;Artifacts&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;○&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;新規ローンチ&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;永続記憶レイヤー&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;Agent Memory&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;○&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;プライベートベータ発表&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;7要件すべてが新規発表・GA昇格・拡張のいずれかに該当します。Agents Week 2026は、Cloudflareがこのレイヤーへの準備を一気に完了させたイベントとして位置づけられます。&lt;&#x2F;p&gt;
&lt;p&gt;次に、Cloud 1.0を制覇した3強(AWS、Google Cloud、Microsoft Azure)にCloudflareを加えて、同じ7要件のものさしで判定します。判定の3条件は次のとおりです。&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;GA: 一般提供されており、誰でも利用できる(プライベートベータや「未公開」は除外)&lt;&#x2F;li&gt;
&lt;li&gt;エージェント特化: 汎用クラウドサービスの流用ではなく、エージェント向けに設計されている&lt;&#x2F;li&gt;
&lt;li&gt;統合プラットフォーム配下: 各社の「エージェントクラウド」ブランドや統合プラットフォームの一部として提供されている&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;3条件すべてを満たせば○、preview&#x2F;beta段階なら△、該当サービスなし・汎用流用・受付終了なら×、と判定します。&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th style=&quot;text-align: left&quot;&gt;要件&lt;&#x2F;th&gt;&lt;th style=&quot;text-align: center&quot;&gt;Cloudflare&lt;&#x2F;th&gt;&lt;th style=&quot;text-align: center&quot;&gt;Google Cloud&lt;&#x2F;th&gt;&lt;th style=&quot;text-align: center&quot;&gt;Microsoft Azure&lt;&#x2F;th&gt;&lt;th style=&quot;text-align: center&quot;&gt;AWS&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;統合推論レイヤー&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;○&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;○&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;○&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;○&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;軽量実行環境&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;△&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;○&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;△&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;△&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;永続Linux環境&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;○&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;○&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;△&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;△&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;エージェント単位プライベートネットワーク&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;△&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;△&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;△&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;×&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;ブラウザ自動化&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;○&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;○&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;×&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;○&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;版管理ストレージ&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;△&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;×&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;×&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;×&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;永続記憶レイヤー&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;△&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;○&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;△&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;○&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;判定の根拠とした各社のエージェント特化プラットフォーム&#x2F;主要サービスは次のとおりです。&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th style=&quot;text-align: left&quot;&gt;要件&lt;&#x2F;th&gt;&lt;th style=&quot;text-align: left&quot;&gt;Cloudflare&lt;&#x2F;th&gt;&lt;th style=&quot;text-align: left&quot;&gt;Google Cloud&lt;&#x2F;th&gt;&lt;th style=&quot;text-align: left&quot;&gt;Microsoft Azure&lt;&#x2F;th&gt;&lt;th style=&quot;text-align: left&quot;&gt;AWS&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;統合推論レイヤー&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;AI Gateway&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;Vertex AI Model Garden&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;Azure AI Foundry Models&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;Amazon Bedrock&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;軽量実行環境&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;Dynamic Workers&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;Cloud Run &#x2F; Vertex AI Agent Engine&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;Azure Container Apps&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;Bedrock AgentCore Runtime&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;永続Linux環境&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;Sandboxes&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;Vertex AI Code Interpreter&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;Azure Container Apps&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;Bedrock AgentCore Code Interpreter&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;エージェント単位プライベートネットワーク&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;Cloudflare Mesh&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;VPC + Vertex AI Agent Engine&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;Azure Private Link + AI Search&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;(PrivateLink等の汎用流用)&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;ブラウザ自動化&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;Browser Run&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;Vertex AI Browser Tool&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;(エージェント特化サービス未確認)&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;Bedrock AgentCore Browser&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;版管理ストレージ&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;Artifacts&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;(該当サービス未確認)&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;(該当サービス未確認)&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;(該当サービス未確認)&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;永続記憶レイヤー&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;Agent Memory&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;Vertex AI Agent Engine Memory Bank&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;Azure AI Foundry Memory&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;Bedrock AgentCore Memory&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;7要件のものさしで眺めると、Google Cloudはエージェント特化のサービスを最も成熟させています。CloudflareはAgents Week 2026で全領域を埋め、×は出していません。Microsoft Azureはエージェント特化の統合プラットフォームとしてはpreview段階のサービスが多い印象です。AWSはBedrock AgentCoreファミリー(Runtime &#x2F; Memory &#x2F; Code Interpreter &#x2F; Browser &#x2F; Gateway &#x2F; Identity &#x2F; Policy &#x2F; Evaluations &#x2F; Observability)でレイヤー横断のサービスを揃えています。特に2026年4月にAgentCore BrowserがOS-levelアクションを追加したことで、ブラウザ自動化は他社と並ぶ水準に到達しています。一方で、エージェント単位のプライベートネットワークとGit互換の版管理ストレージという2領域では、AgentCoreファミリーに対応するプリミティブが現時点で確認できません。&lt;&#x2F;p&gt;
&lt;p&gt;Cloudflareがone-to-one前提の課金モデル(Dynamic Workersのper-load課金、Sandboxesのactive CPU pricing)とisolateベースのms起動を統合的に提供しているのに対し、AWSはAgentCore側で個別プリミティブを揃える方向で追いついている段階です。Cloud 1.0期に確立した汎用プリミティブ(EC2、Lambda、VPC、IAM)はone-to-many前提で設計されていたため、one-to-oneのワークロードに対しては個別最適の積み上げで対応している、と位置づけられます。&lt;&#x2F;p&gt;
&lt;p&gt;Cloud 1.0時代、CDNとセキュリティのベンダーとして3強の外側に置かれていたCloudflareが、Cloud 2.0レイヤーでは3強と肩を並べる側へ上がってきました。Cloud 1.0はAWSが制覇したレイヤーでしたが、Cloud 2.0ではプレイヤーの力関係がリセットされるステージです。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;主戦場は業務リエンジニアリングへ&quot;&gt;主戦場は業務リエンジニアリングへ&lt;&#x2F;h2&gt;
&lt;p&gt;エンタープライズはCloud 1.0の世界を捨てる必要はありません。基幹システムやSaaSバックエンドはAWS中心の運用を続ければよく、その領域でのインフラ・アーキテクチャの設計力はこれからも継続して必要です。&lt;&#x2F;p&gt;
&lt;p&gt;ただしCloud 2.0レイヤーは別の判断軸で組む必要があります。Cloud 1.0期に確立したベンダー選定の前提がそのままでは通じないからです。前節で見たとおり、Cloud 2.0ではGCPが先行、Cloudflareが追いつき、AzureとAWSは個別サービスを揃えつつも統合プラットフォームとしては道半ばです。「Cloud 1.0と同じベンダーで揃える」という発想を出発点にすると、コスト構造とプリミティブの噛み合わせで不利な選択を踏みやすくなります。&lt;&#x2F;p&gt;
&lt;p&gt;そしてCloud 2.0レイヤーで主戦場になるのは、インフラ・アーキテクチャではありません。プラットフォーム側がプリミティブを統合提供している以上、何をどう組み合わせるかが大きな差別化要因にはなりません。&lt;&#x2F;p&gt;
&lt;p&gt;ここで主戦場となるのは、業務プロセスをエージェント向けに再設計し、エージェントのスキルとして実装できる人材です。Cloud 1.0時代に「AWS特化のインフラ設計者」が握っていた価値の中心は、Cloud 2.0では「業務とエージェントの間を設計できる人」に移ります。&lt;&#x2F;p&gt;
&lt;p&gt;エンタープライズが今着手すべきは、エージェントが代替・補強できる業務プロセスの棚卸しと、それをエージェントに落とし込むケイパビリティの社内構築です。Cloud 2.0プラットフォームの選定は、その準備の一部であって目的ではありません。&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;References&quot;&gt;References&lt;&#x2F;h2&gt;
&lt;div class=&quot;references&quot;&gt;
    &lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;blog.cloudflare.com&#x2F;welcome-to-agents-week&#x2F;&quot;&gt;Cloudflare&lt;&#x2F;a&gt;.「Welcome to Agents Week」(米国ナレッジワーカー試算の出典)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;blog.cloudflare.com&#x2F;agents-week-in-review&#x2F;&quot;&gt;Cloudflare&lt;&#x2F;a&gt;.「Building the agentic cloud — Agents Week in Review」(発表総まとめ)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;developers.cloudflare.com&#x2F;changelog&#x2F;post&#x2F;2026-03-24-dynamic-workers-open-beta&#x2F;&quot;&gt;Cloudflare Developers&lt;&#x2F;a&gt;.「Dynamic Workers open beta」(2026年3月24日open beta開放)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;blog.cloudflare.com&#x2F;sandbox-ga&#x2F;&quot;&gt;Cloudflare&lt;&#x2F;a&gt;.「Agents have their own computers with Sandboxes GA」&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;blog.cloudflare.com&#x2F;browser-run-for-ai-agents&#x2F;&quot;&gt;Cloudflare&lt;&#x2F;a&gt;.「Browser Run for AI Agents」&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;blog.cloudflare.com&#x2F;introducing-agent-memory&#x2F;&quot;&gt;Cloudflare&lt;&#x2F;a&gt;.「Introducing Agent Memory」&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.cloudflare.com&#x2F;press&#x2F;press-releases&#x2F;2026&#x2F;cloudflare-launches-mesh-to-secure-the-ai-agent-lifecycle&#x2F;&quot;&gt;Cloudflare Press&lt;&#x2F;a&gt;.「Cloudflare Launches Mesh」&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.anthropic.com&#x2F;news&#x2F;model-context-protocol&quot;&gt;Anthropic&lt;&#x2F;a&gt;.「Model Context Protocol」(2024年11月公開)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;aws.amazon.com&#x2F;bedrock&#x2F;agentcore&#x2F;&quot;&gt;AWS&lt;&#x2F;a&gt;.「Amazon Bedrock AgentCore」(Runtime &#x2F; Memory &#x2F; Code Interpreter &#x2F; Browser &#x2F; Gateway &#x2F; Identity &#x2F; Policy &#x2F; Evaluations &#x2F; Observability)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;aws.amazon.com&#x2F;about-aws&#x2F;whats-new&#x2F;2026&#x2F;04&#x2F;agentcore-browser-os-actions&#x2F;&quot;&gt;AWS&lt;&#x2F;a&gt;.「AgentCore Browser adds OS-level interactions」(2026年4月8日)&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;

&lt;&#x2F;div&gt;
</content>
        <summary type="html">Cloudflareが2026年4月に開催した「Agents Week 2026」では、Cloud 2.0時代の到来が見えてきました。Cloud 1.0で築いた優位がCloud 2.0レイヤーには引き継がれない構造と、エンタープライズが向き合う変化を考えます。
</summary>
        </entry><entry xml:lang="en">
        <title>個人視点で見るAWSのAIサービスの10年</title>
        <published>2026-04-22T10:20:00+09:00</published>
        <updated>2026-04-22T10:20:00+09:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2026/04/aws-ai-twilight/" type="text/html"/>
        <id>https://codedchords.dev/blog/2026/04/aws-ai-twilight/</id>
        
            <content type="html">&lt;!-- textlint-disable --&gt;
&lt;img
  src=&quot;https:&amp;#x2F;&amp;#x2F;codedchords.dev&amp;#x2F;blog&amp;#x2F;2026&amp;#x2F;04&amp;#x2F;aws-ai-twilight&amp;#x2F;cover.webp?h=f94bf393c7b53cec294a&quot;
  alt=&quot;Cover&quot; width=&quot;1536&quot; height=&quot;1024&quot; loading=&quot;lazy&quot;
&#x2F;&gt;&lt;!-- textlint-enable --&gt;
&lt;details&gt;
&lt;summary&gt;Table of Contents&lt;&#x2F;summary&gt;
&lt;!-- toc --&gt;
&lt;&#x2F;details&gt;
&lt;p&gt;かつてAWSのAIは、IAMキー1本と数行のコードで遊べる個人開発者の場所でした。LLM時代の2026年、そこで何が起きたのかを個人の視点から辿ります。&lt;&#x2F;p&gt;
&lt;span id=&quot;continue-reading&quot;&gt;&lt;&#x2F;span&gt;&lt;h2 id=&quot;AWSのAIサービスが革新的だった頃&quot;&gt;AWSのAIサービスが革新的だった頃&lt;&#x2F;h2&gt;
&lt;p&gt;2018年頃の話です。当時、商用AIの旗手とされていたIBM Watsonは、私が直接触れた範囲では期待を裏切る場面が多く、宣伝の勢いと現場感覚のズレが徐々に目立ち始めていた頃でした。&lt;&#x2F;p&gt;
&lt;p&gt;一方、2015年にGoogleが公開したTensorFlowは急速に普及し、「大量のデータを用意して学習させれば、自分の問題を解けるモデルがそのうち作れる」という楽観論も開発者側で盛り上がっていました。ただ、データ収集、アノテーション、訓練用のGPU確保、学習済みモデルのホスティング。どれも個人で完走するには重く、絵に描いた餅で終わることも多かったのが実情です。&lt;&#x2F;p&gt;
&lt;p&gt;そんな中で登場したAWSのAIサービス群は、本当に革新的でした。データを集める必要も、モデルを訓練する必要も、推論用のサーバーを用意する必要もありません。IAMキーと数行のコードさえあれば、訓練済みモデルをAPIとして叩ける。自前の機械学習パイプラインを丸ごとスキップできる衝撃は、今振り返っても大きかったと思います。&lt;&#x2F;p&gt;
&lt;p&gt;翻訳で言えば、DeepLのPro APIが登場したばかりで、Google翻訳APIは法人契約の印象が強く、個人が気軽に叩けるクラウド翻訳APIはAmazon Translateくらいしかありませんでした。&lt;code&gt;curl&lt;&#x2F;code&gt;で一発叩くだけでなく、ちょっとしたCLIツールを自作することも多く、その一例として、私自身もIBM時代にAmazon Translateをバックエンドに採用した社内向けラッパーツールを書いたことがあります。このツールはWord・Excel・PowerPointのファイルを日英相互翻訳していました。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;個人ユーザーにはLLMで十分な時代&quot;&gt;個人ユーザーにはLLMで十分な時代&lt;&#x2F;h2&gt;
&lt;p&gt;かつてのAWSには、機械学習をブラックボックスのまま呼び出せるAPI群がきれいに揃っていました。翻訳はTranslate、画像解析はRekognition、自然言語処理はComprehend、帳票はTextract、音声合成はPolly。自前で学習データを集める必要はなく、IAMキーと数行のコードさえあれば機能を呼び出せました。この「気軽さ」こそが、当時の個人開発者にとっての魅力でした。&lt;&#x2F;p&gt;
&lt;p&gt;ところが今、同じ機能の大半はLLMに直接投げれば済むようになりました。&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;サービス&lt;&#x2F;th&gt;&lt;th&gt;機能&lt;&#x2F;th&gt;&lt;th&gt;LLM時代の代替&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;Amazon Translate&lt;&#x2F;td&gt;&lt;td&gt;ニューラル機械翻訳API（多言語対応）&lt;&#x2F;td&gt;&lt;td&gt;GPT&#x2F;Claude&#x2F;Geminiに訳文を直接依頼。DeepL Pro APIも成熟&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Amazon Rekognition&lt;&#x2F;td&gt;&lt;td&gt;画像・動画解析（物体検出、顔認識、モデレーション、テキスト検出）&lt;&#x2F;td&gt;&lt;td&gt;ビジョン対応LLM（GPT-4o、Claude、Gemini）に画像を渡して記述や抽出を頼む&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Amazon Comprehend&lt;&#x2F;td&gt;&lt;td&gt;自然言語処理（エンティティ抽出、感情分析、キーフレーズ抽出、言語判定）&lt;&#x2F;td&gt;&lt;td&gt;同じ処理をLLMへの1プロンプトで任せる&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Amazon Textract&lt;&#x2F;td&gt;&lt;td&gt;書類のOCRとフォーム・表の構造化抽出&lt;&#x2F;td&gt;&lt;td&gt;ビジョン対応LLMに直接PDF・画像を渡して構造化JSONを返させる&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Amazon Polly&lt;&#x2F;td&gt;&lt;td&gt;ニューラル音声合成（TTS）&lt;&#x2F;td&gt;&lt;td&gt;OpenAI TTS、ElevenLabs、Gemini Native Speechなど生成AI系音声モデル&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;個人のツールや単発のトランザクションで、わざわざ用途別のAPIを選んで使う意味は、ほとんど残っていません。画像の内容を説明してほしければ、ClaudeやGPTに画像をそのまま渡せば事足ります。領収書から項目を抜き出したいときも、PDFをLLMに渡してJSONで返すよう頼めば済みます。APIの名前を覚え、サービスごとに異なる出力フォーマットを吸収する手間と比べて、LLMに自然言語で頼む方が圧倒的に速いからです。&lt;&#x2F;p&gt;
&lt;p&gt;もっとも、これはあくまで個人開発者のツールや単発利用の話です。エンタープライズの大量処理では、これらのAPIは現在もLLMパイプラインの前処理部品として現役です。例えば、TextractでPDFを構造化してからLLMに渡す、Translateで多言語テキストを統一する、ComprehendでPIIをマスクしてから生成系に流すといった使い方が典型です。&lt;&#x2F;p&gt;
&lt;p&gt;理由は、個人利用では意識する必要のない要件が企業では避けられないからです。LLMは同じ入力でも出力が揺れ、ハルシネーションを起こし、大量処理ではトークン課金が嵩みます。一方、Textractのような専用APIは決定的な出力を返し、料金もページ単価で桁違いに安く、出力形式が固定なので監査ログやSLA契約にも馴染みます。個人の単発処理ではこれらの差が表面化しないため、LLM直叩きの手軽さが勝るのです。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;AWSのLLMはエンタープライズのために&quot;&gt;AWSのLLMはエンタープライズのために&lt;&#x2F;h2&gt;
&lt;p&gt;前節で見たように、かつてのAIサービスは個人視点ではLLMに置き換えられました。ではAWSはこの流れにどう応えたのでしょうか。自前で競争力のあるLLMを持たないAWSが出した答えは、外部のモデル提供者を集めて統一APIで呼び出せるようにしたBedrockでした。&lt;&#x2F;p&gt;
&lt;p&gt;2026年4月時点では、Anthropic (Claude) を筆頭に、Amazon自社のNovaとTitan、Meta (Llama)、Mistral、OpenAI、DeepSeek、Cohere、AI21 Labsなど、十数社・100モデル超が並びます。OpenAIのオープンウェイトモデル（gpt-oss系）までBedrockから呼べるようになったのは2025年の大きな動きでした。モデルの厚みだけを見れば、単一ベンダーの直接APIよりも広い選択肢が用意されているとも言えます&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-converse-1&quot;&gt;&lt;a href=&quot;#fn-converse&quot;&gt;1&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;。&lt;&#x2F;p&gt;
&lt;p&gt;ただ、Bedrockの価値の本体はモデル選択の自由そのものではなく、&lt;strong&gt;AWSの枠組みへ組み込まれていること&lt;&#x2F;strong&gt;にあります。既存のIAMポリシーで権限を統制でき、VPCエンドポイントでインターネットを経由せず呼び出せ、CloudTrailで全ての呼び出しを監査でき、利用料はAWSの単一請求にまとまります。データが既にS3にある組織では、そこからRetrieval Augmented Generationへ繋ぐ道もBedrockの中で完結します。既にAWS上に業務基盤がある企業にとっては、こうした統合こそがBedrockを選ぶ最大の理由です。&lt;&#x2F;p&gt;
&lt;p&gt;一方で、個人開発者がBedrockを介する恩恵はほとんど残っていません。新モデルの到達はAnthropicやOpenAIの直接APIより遅れることが多く、IAMやリージョンの設定、モデルアクセス申請といったセットアップの重さも、APIキー1本で始められる本家との差としてのしかかります。かつてIAMキーと数行のコードから始められたAWS AIサービスの気軽さは、LLM時代には失われたと言って良いでしょう。&lt;&#x2F;p&gt;
&lt;p&gt;つまり、AWSがLLM時代に出した答えは、AWSを既に使っている企業への最適化でした。AWSが誰を主な顧客として見ているのか、この選択そのものが物語っています。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;まとめ&quot;&gt;まとめ&lt;&#x2F;h2&gt;
&lt;p&gt;個人から見たAWSのAIは、この10年で位置づけを大きく変えました。IAMキーと数行のコードで訓練済みモデルを叩ける気軽さは、LLMの登場によって個人視点では蒸発しています。翻訳、画像解析、帳票処理のいずれも、ClaudeやGPTに直接渡す方が速く柔軟で、専用APIを選ぶ理由はほとんど残っていません。&lt;&#x2F;p&gt;
&lt;p&gt;LLM時代の本命であるBedrockも、個人開発者にとっては分が悪い選択肢です。その価値はIAM&#x2F;VPC&#x2F;監査&#x2F;単一請求といった統合レイヤーにあり、新モデル到達は直接APIより遅れ、セットアップも重く、モデル選択肢の広さも個人が手軽に享受できる形にはなっていません。&lt;&#x2F;p&gt;
&lt;p&gt;個人向けの例外として、コード補完のAmazon Q Developerには無料枠があります。しかし実際の現場ではGitHub Copilot、Cursor、Claude Codeが競合し、Q Developerがデフォルトに選ばれる場面はほとんど見かけません。AWSが個人向け枠を用意している事実と、個人がそこを選んでいない事実は両立しています。&lt;&#x2F;p&gt;
&lt;p&gt;AWSのAIは個人から離れたわけではなく、&lt;strong&gt;個人が期待する形では競争に勝てていない&lt;&#x2F;strong&gt;、というのが正直な現状でしょう。Bedrock、SageMaker、Q Businessといった現在のAI製品群は、企業の業務システムと不可分な形で組み立てられています。かつてAWSにあった「IAMキーと数行のコードで叩ける個人の遊び場」としての姿は、もう見つけにくくなっています。&lt;&#x2F;p&gt;
&lt;section class=&quot;footnotes&quot;&gt;
&lt;ol class=&quot;footnotes-list&quot;&gt;
&lt;li id=&quot;fn-converse&quot;&gt;
&lt;p&gt;こういった機能説明を読むと「Bedrockではマルチモデルを統一したインターフェイスで扱える」と期待するかも知れません。たしかにBedrockには統一メッセージ形式でモデル差し替えを可能にするConverse APIもあります。ただし、モデルごとに対応したプロンプトチューニングは必要ですし挙動もモデルごとに異なるため、Converse APIだから簡単に差し替え可能と言うわけではありません。また、当然ながらモデル固有機能は利用できません。 &lt;a href=&quot;#fr-converse-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;&#x2F;section&gt;
</content>
        <summary type="html">かつて「IAMキー1本で訓練済みAPIを叩ける気軽さ」が魅力だったAWSのAI。LLM時代に個人視点で何が残っているかを、BedrockとAmazon Q Developerまで含めて観察します。</summary>
        </entry><entry xml:lang="en">
        <title>GoFデザインパターンは現代でも有用か(4) — 現代でも有用なパターンとまとめ</title>
        <published>2026-04-06T08:06:00+09:00</published>
        <updated>2026-04-06T08:06:00+09:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2026/04/gof-design-patterns/04-essential-patterns/" type="text/html"/>
        <id>https://codedchords.dev/blog/2026/04/gof-design-patterns/04-essential-patterns/</id>
        
            <content type="html">&lt;!-- textlint-disable --&gt;
&lt;img
  src=&quot;https:&amp;#x2F;&amp;#x2F;codedchords.dev&amp;#x2F;blog&amp;#x2F;2026&amp;#x2F;04&amp;#x2F;gof-design-patterns&amp;#x2F;04-essential-patterns&amp;#x2F;cover.webp?h=625c502b1c7f13dd5ea6&quot;
  alt=&quot;Cover&quot; width=&quot;1792&quot; height=&quot;1024&quot; loading=&quot;lazy&quot;
&#x2F;&gt;&lt;!-- textlint-enable --&gt;
&lt;details&gt;
&lt;summary&gt;Table of Contents&lt;&#x2F;summary&gt;
&lt;!-- toc --&gt;
&lt;&#x2F;details&gt;
&lt;h2 id=&quot;前回までの振り返り&quot;&gt;前回までの振り返り&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;codedchords.dev&#x2F;blog&#x2F;2026&#x2F;04&#x2F;gof-design-patterns&#x2F;01-paradigm-shift&#x2F;&quot;&gt;第1回&lt;&#x2F;a&gt;では、OOPのパラダイムシフトとGoFデザインパターンの誕生、そしてGo言語による脱OOPの流れを振り返りました。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;codedchords.dev&#x2F;blog&#x2F;2026&#x2F;04&#x2F;gof-design-patterns&#x2F;02-unnecessary-patterns&#x2F;&quot;&gt;第2回&lt;&#x2F;a&gt;では、Go言語の3つの設計方針がGoFの23パターンのうち10パターンを不要にしたことを検証しました。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;codedchords.dev&#x2F;blog&#x2F;2026&#x2F;04&#x2F;gof-design-patterns&#x2F;03-useful-patterns&#x2F;&quot;&gt;第3回&lt;&#x2F;a&gt;では、残る13パターンのうち、言語機能として取り込まれたIteratorと、現代の設計手法により非推奨となったSingletonを検討しました。&lt;&#x2F;p&gt;
&lt;!-- textlint-disable --&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;分類&lt;&#x2F;th&gt;&lt;th&gt;パターン&lt;&#x2F;th&gt;&lt;th&gt;状態&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;OOPの制約への処方箋（第2回）&lt;&#x2F;td&gt;&lt;td&gt;Template Method, Factory Method, Abstract Factory, Bridge, Prototype, Memento, Strategy, Command, Visitor, Observer&lt;&#x2F;td&gt;&lt;td&gt;不要&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;言語機能として吸収（第3回）&lt;&#x2F;td&gt;&lt;td&gt;Iterator&lt;&#x2F;td&gt;&lt;td&gt;意識不要&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;設計手法の進化で非推奨（第3回）&lt;&#x2F;td&gt;&lt;td&gt;Singleton&lt;&#x2F;td&gt;&lt;td&gt;非推奨&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;!-- textlint-enable --&gt;
&lt;p&gt;本記事では、残る11のパターンがなぜ現代でも有用なのかを分析し、シリーズ全体の結論としてデザインパターンの本質的価値を考察します。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;現代でも有用なパターン&quot;&gt;現代でも有用なパターン&lt;&#x2F;h2&gt;
&lt;p&gt;残る11のパターンは、継承と参照セマンティクスのいずれにも依存していません。ここまで見てきたパターンがOOPの言語メカニズムへの処方箋だったのに対し、これらはOOPとは無関係に存在する、ソフトウェア設計の普遍的な課題を解決するものです。つまり、GoFの23パターンの中にはOOPの処方箋と、言語に依存しない設計の原則「ソフトウェアアーキテクチャの原則」が混在していたのです。&lt;&#x2F;p&gt;
&lt;p&gt;生き残ったパターンを、その理由ごとに分類します。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;小さな部品を合成して大きな振る舞いを作る&quot;&gt;小さな部品を合成して大きな振る舞いを作る&lt;&#x2F;h3&gt;
&lt;p&gt;Go言語の設計思想「継承より合成（composition over inheritance）」と直結する分類です。小さな部品を組み合わせて複雑な構造や振る舞いを構築するという原則は、プログラミングパラダイムを問わず有効です。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Composite&lt;&#x2F;strong&gt; — 再帰的なツリー構造を合成し、個々の要素と合成要素を同一視する。ファイルシステムやUIコンポーネントなど、階層構造を持つあらゆる領域で使われる&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Decorator&lt;&#x2F;strong&gt; — 既存の機能に新しい責務を動的に重ね合わせる。Go言語では&lt;code&gt;http.Handler&lt;&#x2F;code&gt;をラップするミドルウェアパターンとして標準的に使われている&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Chain of Responsibility&lt;&#x2F;strong&gt; — 処理を連鎖させ、リクエストを適切なハンドラに委譲する。Go言語のHTTPミドルウェアチェーンそのもの&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Builder&lt;&#x2F;strong&gt; — 複雑なオブジェクトを段階的に構築する。Go言語ではfunctional optionsパターンとして定着している&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;コンポーネント間の境界を制御する&quot;&gt;コンポーネント間の境界を制御する&lt;&#x2F;h3&gt;
&lt;p&gt;ソフトウェアの規模が大きくなると、コンポーネント間の依存関係やインターフェースの不一致が複雑さの主要因になります。この問題に対処するパターンは、言語やパラダイムに関係なく必要です。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Adapter&lt;&#x2F;strong&gt; — 互換性のないインターフェース同士を橋渡しする。外部ライブラリやレガシーシステムとの統合で常に必要になる&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Facade&lt;&#x2F;strong&gt; — 複雑なサブシステムに対して統一的な窓口を提供する。Go言語ではパッケージの公開APIを絞ることで自然に実現される&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Proxy&lt;&#x2F;strong&gt; — 対象へのアクセスを制御する代理を提供する。遅延初期化、アクセス制御、ログ記録など用途が幅広い&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Mediator&lt;&#x2F;strong&gt; — 多対多のオブジェクト間の相互作用を仲介者に集約し、疎結合にする。イベントバスやメッセージブローカーの設計に通じる&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;状態に応じて振る舞いを切り替える&quot;&gt;状態に応じて振る舞いを切り替える&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;State&lt;&#x2F;strong&gt; — 内部状態に応じてオブジェクトの振る舞いを変更する。Go言語ではStateインターフェースを定義し、状態ごとに異なる型で実装する。有限状態マシンの設計に直結する&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;特定領域の問題を解決する&quot;&gt;特定領域の問題を解決する&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Flyweight&lt;&#x2F;strong&gt; — 多数の細粒度オブジェクトの共有によりメモリ使用量を削減する。文字列のインターン化やキャッシュなど、メモリ最適化が必要な場面で有効&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Interpreter&lt;&#x2F;strong&gt; — 言語の文法を定義し解釈する。DSL（ドメイン固有言語）や設定ファイルのパーサー、式評価エンジンなど、特定の用途で使われる&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;まとめ_—_デザインパターンの本質的価値とは何だったのか&quot;&gt;まとめ — デザインパターンの本質的価値とは何だったのか&lt;&#x2F;h2&gt;
&lt;p&gt;GoFの功績は、コード内で繰り返し現れるパターンに名前を付け、&lt;strong&gt;開発者の共通言語&lt;&#x2F;strong&gt;を確立したことにあります。「ここはObserverで」「Adapterを挟もう」と言えば設計意図が伝わる。この語彙の確立は、ソフトウェア開発の生産性に大きく貢献しました。&lt;&#x2F;p&gt;
&lt;p&gt;しかし、本記事の分析が示すように、GoFの23パターンには性質の異なる2種類のものが混在していました。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;実装の工夫&lt;&#x2F;strong&gt; : パラダイムシフトを起こしたばかりのOOPの未成熟さをカバーするもの。継承の副作用を管理するTemplate MethodやVisitor、参照セマンティクスを補完するPrototypeやMemento。これらはOOPという特定のパラダイムの制約の中で必要だった処方箋であり、パラダイムが変われば不要になるもの。&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;普遍的な設計原則&lt;&#x2F;strong&gt; - 合成による構築、境界の制御など設計のベストプラクティス。CompositeやDecorator、AdapterやFacadeは、OOPとは無関係に、ソフトウェアの複雑さに対処するためのアーキテクチャの知恵。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;GoFの問題は、この2つがあまり区別されず、同列にカタログ化されたことです。そして当時、OOPが成熟した段階を経験したプログラマが少なかったことも相まって、GoFは必要以上に神格化されました。
本来はコードレベルの実装パターンであるにもかかわらず、当時は業務システムのアーキテクチャを語る場面でGoFのパターン名が持ち出されるような頓珍漢なエンジニアさえ出現しました。デザインパターンは「設計パターン」と訳されますが、実態は「コードパターン」であったことに留意すべきです。&lt;&#x2F;p&gt;
&lt;p&gt;Go言語が示したのは、OOPの制約に起因するパターンは言語設計で解消できるということです。そして残った11のパターンこそが、GoFの本質的な遺産「言語やパラダイムを超えた設計原則」だったと言えます。&lt;&#x2F;p&gt;
&lt;p&gt;ただし、この結論すら永続的なものではありません。Rustの列挙型とパターンマッチングはStateパターンを言語機能として吸収しつつありますし、名前付き引数やデフォルト値を持つ言語ではBuilderの必要性が薄れます。今日「普遍的な設計原則」に見えるものも、将来の言語やパラダイムの進化によって、さらに整理されていく可能性があります。&lt;&#x2F;p&gt;
&lt;p&gt;デザインパターンの本質的な価値は、23のカタログそのものにはありませんでした。ソフトウェアの複雑さに名前を付け、共有可能な知識として体系化しようとした試み「その営み」こそが、GoFの真の貢献だったのではないでしょうか。&lt;&#x2F;p&gt;
&lt;p&gt;本シリーズで取り上げたGoFの23パターンすべてをGo言語で実装したサンプルコードを公開しています。&lt;&#x2F;p&gt;
&lt;!-- textlint-disable --&gt;
&lt;iframe class=&quot;hatenablogcard&quot; src=&quot;https:&#x2F;&#x2F;hatenablog-parts.com&#x2F;embed?url=https:&amp;#x2F;&amp;#x2F;github.com&amp;#x2F;yostos&amp;#x2F;gof-go-samples&quot; width=&quot;100%&quot; height=&quot;155&quot; frameborder=&quot;0&quot; scrolling=&quot;no&quot; loading=&quot;lazy&quot;&gt;&lt;&#x2F;iframe&gt;
&lt;!-- textlint-enable --&gt;
</content>
        <summary type="html">連載最終回。GoFの23パターンのうち、OOPに依存しない11のパターンは現代でも有用です。なぜ生き残ったのかを分析し、デザインパターンの本質的価値を考察します。</summary>
        </entry><entry xml:lang="en">
        <title>GoFデザインパターンは現代でも有用か(3) — 言語に吸収されたパターンと非推奨のSingleton</title>
        <published>2026-04-02T10:15:00+09:00</published>
        <updated>2026-04-02T10:15:00+09:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2026/04/gof-design-patterns/03-useful-patterns/" type="text/html"/>
        <id>https://codedchords.dev/blog/2026/04/gof-design-patterns/03-useful-patterns/</id>
        
            <content type="html">&lt;!-- textlint-disable --&gt;
&lt;img
  src=&quot;https:&amp;#x2F;&amp;#x2F;codedchords.dev&amp;#x2F;blog&amp;#x2F;2026&amp;#x2F;04&amp;#x2F;gof-design-patterns&amp;#x2F;03-useful-patterns&amp;#x2F;cover.webp?h=ab1a8a011510459a068c&quot;
  alt=&quot;Cover&quot; width=&quot;1792&quot; height=&quot;1024&quot; loading=&quot;lazy&quot;
&#x2F;&gt;&lt;!-- textlint-enable --&gt;
&lt;details&gt;
&lt;summary&gt;Table of Contents&lt;&#x2F;summary&gt;
&lt;!-- toc --&gt;
&lt;&#x2F;details&gt;
&lt;h2 id=&quot;前回までの振り返り&quot;&gt;前回までの振り返り&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;codedchords.dev&#x2F;blog&#x2F;2026&#x2F;04&#x2F;gof-design-patterns&#x2F;01-paradigm-shift&#x2F;&quot;&gt;第1回&lt;&#x2F;a&gt;では、手続き型プログラミングからOOPへのパラダイムシフト、その中でGoFデザインパターンが「OOPでよいコードを書くためのお手本」として体系化された経緯を振り返りました。そして現代では、OOPの中核 — クラス継承、型階層、参照セマンティクス — を意図的に排除したGo言語が登場し、新たなパラダイムシフトが起きていることを確認しました。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;codedchords.dev&#x2F;blog&#x2F;2026&#x2F;04&#x2F;gof-design-patterns&#x2F;02-unnecessary-patterns&#x2F;&quot;&gt;第2回&lt;&#x2F;a&gt;では、Go言語の3つの設計方針がGoFの23パターンのうち10パターンを不要にしたことを検証しました。&lt;&#x2F;p&gt;
&lt;!-- textlint-disable --&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Go言語の設計方針&lt;&#x2F;th&gt;&lt;th&gt;不要になったパターン&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;クラス継承を排除し、合成と暗黙的インターフェースで代替&lt;&#x2F;td&gt;&lt;td&gt;Template Method, Factory Method, Abstract Factory, Bridge&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;参照セマンティクスではなく値セマンティクスをデフォルトに&lt;&#x2F;td&gt;&lt;td&gt;Prototype, Memento&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;振る舞いもオブジェクトに包む制約を廃し、第一級関数とチャネル&#x2F;ゴルーチンで直接扱えるように&lt;&#x2F;td&gt;&lt;td&gt;Strategy, Command, Visitor, Observer&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;!-- textlint-enable --&gt;
&lt;p&gt;これらはOOPの制約の中で生まれた処方箋であり、制約そのものを取り除いたGo言語では必要なくなったものでした。では、残る13パターンはどうでしょうか。本記事では、言語機能として取り込まれたものと、設計手法の進化で非推奨となったものを検討します。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;言語機能として取り込まれたパターン&quot;&gt;言語機能として取り込まれたパターン&lt;&#x2F;h2&gt;
&lt;p&gt;デザインパターンの中には、その有用性が広く認められた結果、現代の言語では標準的な機能として取り込まれたものがあります。デザインパターンが語られた当時はOOPがまだ成熟しておらず、これらの機能をユーザーで実装していたとも言えます。これらのパターンは「不要になった」のではなく、「わざわざパターンとして意識する必要がなくなった」と言えます。&lt;&#x2F;p&gt;
&lt;p&gt;Go言語も例外でなく、言語仕様としてこれらのパターンを取り込んでいます。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;コレクションの内部構造を公開せずに要素を走査する&quot;&gt;コレクションの内部構造を公開せずに要素を走査する&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Iterator&lt;&#x2F;strong&gt; — イテレータオブジェクトを別途定義し、&lt;code&gt;hasNext()&lt;&#x2F;code&gt;&#x2F;&lt;code&gt;next()&lt;&#x2F;code&gt;のようなインターフェースを実装する必要があった&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;『&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;amzn.to&#x2F;4bW36Po&quot;&gt;Java言語で学ぶデザインパターン入門&lt;&#x2F;a&gt;第3版』(結城浩著)&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-affiliate-1&quot;&gt;&lt;a href=&quot;#fn-affiliate&quot;&gt;1&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;のIteratorパターンのサンプルコードを見てみます。本棚（BookShelf）に本（Book）を格納し、イテレータで順に取り出すという例です。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;java&quot; data-name=&quot;Book.java&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-modifier&quot;&gt;public class&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; Book&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-modifier z-storage z-type&quot;&gt;    private String&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; name&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-modifier&quot;&gt;    public&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; Book&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;String&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt; name&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable z-language z-this&quot;&gt;        this&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;name&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; name&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-modifier z-storage z-type&quot;&gt;    public String&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; getName&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;() {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;        return&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; name&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;java&quot; data-name=&quot;BookShelf.java&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;import&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-modifier z-import z-java&quot;&gt; java&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-modifier z-import z-java&quot;&gt;util&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-modifier z-import z-java&quot;&gt;Iterator&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-modifier&quot;&gt;public class&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; BookShelf&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-modifier z-implements&quot;&gt; implements&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-other z-inherited-class&quot;&gt; Iterable&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;Book&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-modifier z-storage z-type&quot;&gt;    private Book&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[]&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; books&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-modifier z-storage z-type&quot;&gt;    private int&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; last&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 0&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-modifier&quot;&gt;    public&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; BookShelf&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;int&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt; maxsize&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable z-language z-this&quot;&gt;        this&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;books&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-storage z-type&quot;&gt; new Book&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;maxsize&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;];&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-modifier z-storage z-type&quot;&gt;    public Book&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; getBookAt&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;int&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt; index&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;        return&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; books&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;index&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;];&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-modifier z-storage z-type&quot;&gt;    public void&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; appendBook&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;Book&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt; book&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable z-language z-this&quot;&gt;        this&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;books&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;last&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; book&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;        last&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;++&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-modifier z-storage z-type&quot;&gt;    public int&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; getLength&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;() {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;        return&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; last&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-annotation z-storage z-type z-annotation&quot;&gt;    @Override&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-modifier z-storage z-type&quot;&gt;    public Iterator&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;Book&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; iterator&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;() {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;        return new&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; BookShelfIterator&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-language z-this&quot;&gt;this&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;java&quot; data-name=&quot;BookShelfIterator.java&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;import&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-modifier z-import z-java&quot;&gt; java&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-modifier z-import z-java&quot;&gt;util&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-modifier z-import z-java&quot;&gt;Iterator&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;import&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-modifier z-import z-java&quot;&gt; java&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-modifier z-import z-java&quot;&gt;util&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-modifier z-import z-java&quot;&gt;NoSuchElementException&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-modifier&quot;&gt;public class&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; BookShelfIterator&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-modifier z-implements&quot;&gt; implements&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-other z-inherited-class&quot;&gt; Iterator&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;Book&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-modifier z-storage z-type&quot;&gt;    private BookShelf&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; bookShelf&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-modifier z-storage z-type&quot;&gt;    private int&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; index&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-modifier&quot;&gt;    public&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; BookShelfIterator&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;BookShelf&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt; bookShelf&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable z-language z-this&quot;&gt;        this&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;bookShelf&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; bookShelf&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable z-language z-this&quot;&gt;        this&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;index&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 0&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-annotation z-storage z-type z-annotation&quot;&gt;    @Override&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-modifier z-storage z-type&quot;&gt;    public boolean&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; hasNext&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;() {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;        if&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; (&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;index &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; bookShelf&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;getLength&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;()) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;            return&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language&quot;&gt; true&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;        }&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; else&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;            return&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language&quot;&gt; false&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;        }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-annotation z-storage z-type z-annotation&quot;&gt;    @Override&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-modifier z-storage z-type&quot;&gt;    public Book&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; next&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;() {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;        if&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; (&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;!&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;hasNext&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;()) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;            throw new&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; NoSuchElementException&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;        }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;        Book&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; book&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; bookShelf&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;getBookAt&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;index&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;        index&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;++&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;        return&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; book&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;java&quot; data-name=&quot;Main.java&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;import&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-modifier z-import z-java&quot;&gt; java&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-modifier z-import z-java&quot;&gt;util&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-modifier z-import z-java&quot;&gt;Iterator&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-modifier&quot;&gt;public class&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; Main&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-modifier z-storage z-type&quot;&gt;    public static void&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; main&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;String&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[]&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt; args&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;        BookShelf&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; bookShelf&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; new&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; BookShelf&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;4&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;        bookShelf&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;appendBook&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;new&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; Book&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;Around the World in 80 Days&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;));&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;        bookShelf&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;appendBook&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;new&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; Book&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;Bible&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;));&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;        bookShelf&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;appendBook&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;new&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; Book&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;Cinderella&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;));&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;        bookShelf&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;appendBook&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;new&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; Book&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;Daddy-Long-Legs&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;));&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;        &#x2F;&#x2F; 明示的にIteratorを使う方法&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;        Iterator&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;Book&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; it&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; bookShelf&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;iterator&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;        while&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; (&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;it&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;hasNext&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;()) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;            Book&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; book&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; it&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;next&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;            System&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;out&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;println&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;book&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;getName&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;());&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;        }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;        System&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;out&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;println&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;        &#x2F;&#x2F; 拡張for文を使う方法&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;        for&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; (&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;Book&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; book&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; bookShelf&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;            System&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;out&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;println&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;book&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;getName&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;());&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;        }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;        System&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;out&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;println&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;!-- textlint-disable --&gt;
&lt;!-- author-approved: MIT License sample code credit --&gt;
&lt;p&gt;上記Javaコードは結城浩氏によるサンプルコード（&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.hyuki.com&#x2F;dp&#x2F;&quot;&gt;MIT License&lt;&#x2F;a&gt;、Copyright (c) 2001,2004,2021 結城浩 &#x2F; Hiroshi Yuki）です。&lt;&#x2F;p&gt;
&lt;!-- textlint-enable --&gt;
&lt;p&gt;4つのファイル、約80行のコードが必要です。&lt;code&gt;BookShelfIterator&lt;&#x2F;code&gt;クラスが走査の状態（現在のインデックス）を管理し、&lt;code&gt;hasNext()&lt;&#x2F;code&gt;と&lt;code&gt;next()&lt;&#x2F;code&gt;のインターフェースを実装しています。&lt;code&gt;BookShelf&lt;&#x2F;code&gt;は&lt;code&gt;Iterable&amp;lt;Book&amp;gt;&lt;&#x2F;code&gt;を実装し、&lt;code&gt;iterator()&lt;&#x2F;code&gt;メソッドでイテレータを生成します。&lt;&#x2F;p&gt;
&lt;p&gt;Go言語で同じBookShelfを書くとどうなるでしょうか。Go 1.23で導入されたrange-over-function（&lt;code&gt;iter.Seq&lt;&#x2F;code&gt;）を使うと、Javaと同等のカスタムコレクションを以下のように実装できます。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;go&quot; data-name=&quot;main.go&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;package&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; main&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;import&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; (&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;    &amp;quot;fmt&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;    &amp;quot;iter&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;type&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; Book&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; struct&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    Name&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt; string&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;type&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; BookShelf&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; struct&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    books&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; []&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt;Book&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;func&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; (&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt;s &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt;BookShelf&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; Append&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt;book&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; Book&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    s&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;books&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; append&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;s&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;books&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; book&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;func&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; (&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt;s &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt;BookShelf&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; All&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;()&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; iter&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt;Seq&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt;Book&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;] {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;    return func&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt;yield&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; func&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt;Book&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt; bool&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;        for&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; _&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; book&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; :=&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; range&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; s&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;books&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;            if&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; !&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;yield&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;book&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;                return&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;            }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;        }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;func&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; main&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;() {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    shelf&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; := &amp;amp;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt;BookShelf&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;{}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    shelf&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;Append&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt;Book&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;Name&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;Around the World in 80 Days&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;})&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    shelf&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;Append&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt;Book&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;Name&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;Bible&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;})&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    shelf&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;Append&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt;Book&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;Name&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;Cinderella&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;})&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    shelf&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;Append&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt;Book&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;Name&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;Daddy-Long-Legs&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;})&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;    for&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; book&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; :=&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; range&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; shelf&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;All&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;() {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;        fmt&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;Println&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;book&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;Name&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Javaでは&lt;code&gt;Iterable&lt;&#x2F;code&gt;インターフェース、&lt;code&gt;Iterator&lt;&#x2F;code&gt;実装クラス、&lt;code&gt;hasNext()&lt;&#x2F;code&gt;&#x2F;&lt;code&gt;next()&lt;&#x2F;code&gt;メソッドの3層が必要でした。Go言語では&lt;code&gt;iter.Seq&lt;&#x2F;code&gt;型の関数を1つ返すだけで済みます。イテレータの状態管理（インデックスの保持、終端判定）はクロージャが担い、専用のクラスを書く必要がありません。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;現代の設計手法により非推奨となったパターン&quot;&gt;現代の設計手法により非推奨となったパターン&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;インスタンスが1つだけであることを保証する&quot;&gt;インスタンスが1つだけであることを保証する&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Singleton&lt;&#x2F;strong&gt; — クラスのインスタンスが1つだけであることを保証し、グローバルなアクセス手段を提供する&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;典型的な例として、アプリケーションの設定情報（Config）をSingletonで管理するケースを見てみます。Go言語で実装した例です。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;go&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;var&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; (&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    instance&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; *&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt;Config&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    once&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt;     sync&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt;Once&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;type&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; Config&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; struct&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    DBHost&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt; string&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    DBPort&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt; int&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;func&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; GetConfig&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;()&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; *&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt;Config&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    once&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;Do&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;func&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;() {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;        port&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; _&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; :=&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; strconv&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;Atoi&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;os&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;Getenv&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;DB_PORT&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;))&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;        instance&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; = &amp;amp;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt;Config&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;            DBHost&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; os&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;Getenv&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;DB_HOST&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;            DBPort&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; port&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;        }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    })&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;    return&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; instance&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;type&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; UserRepository&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; struct&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;{}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;func&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; (&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt;r &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt;UserRepository&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; FindByID&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt;id&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt; int&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;) (&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt;User&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt; error&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;    &#x2F;&#x2F; どこからでもGetConfig()でアクセスできる&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    config&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; :=&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; GetConfig&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    dsn&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; :=&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; fmt&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;Sprintf&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;%s:%d&#x2F;mydb&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; config&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;DBHost&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; config&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;DBPort&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;    &#x2F;&#x2F; ...&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Configのようなオブジェクトは、システムにインスタンスを1つだけ持つのが都合よいものです。そのため、このような実装が広く行われていました。
しかし、テストのシーンを考えると、このパターンは問題があります。
&lt;code&gt;UserRepository&lt;&#x2F;code&gt;は&lt;code&gt;Config&lt;&#x2F;code&gt;に依存していますが、その依存は関数の引数に現れません。
テスト時に本番と異なる設定を注入することも困難です。&lt;&#x2F;p&gt;
&lt;p&gt;Singletonは、OOPの副作用とは無関係に、現代の多くの設計指針で非推奨とされるパターンです。問題の本質は「インスタンスが1つ」であることではなく、「グローバルなアクセス手段を提供する」という点にあります。&lt;code&gt;GetConfig()&lt;&#x2F;code&gt;のようなグローバル関数を通じてどこからでもアクセスできることが、隠れた依存関係を生み、テスト時のモック差し替えを困難にします。&lt;&#x2F;p&gt;
&lt;p&gt;注意すべきは、「ライフサイクルとしてのシングルトン」まで否定しているわけではないことです。DIコンテナがオブジェクトのスコープをシングルトンとして管理すること（SpringのデフォルトスコープやGoのfxにおけるライフサイクル管理など）は、依存関係が明示的である限り問題ありません。非推奨なのは、GoFが定義した「グローバルアクセスを提供するパターンとしてのSingleton」です。&lt;&#x2F;p&gt;
&lt;p&gt;現代では、依存性の注入（Dependency Injection）がこの問題に対するより優れた解法として確立されています。必要な依存を明示的に引数として渡すことで、グローバル状態を排除し、テスト容易性と可読性を確保します。同じ設計をDIで書くと次のようになります。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;go&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;type&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; Config&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; struct&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    DBHost&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt; string&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    DBPort&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt; int&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;type&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; UserRepository&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; struct&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    config&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; Config&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;func&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; NewUserRepository&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt;config&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; Config&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; *&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt;UserRepository&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;    return&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; &amp;amp;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt;UserRepository&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;config&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; config&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;func&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; (&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt;r &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt;UserRepository&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; FindByID&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt;id&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt; int&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;) (&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt;User&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt; error&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    dsn&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; :=&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; fmt&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;Sprintf&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;%s:%d&#x2F;mydb&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; r&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;config&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;DBHost&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; r&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;config&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;DBPort&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;    &#x2F;&#x2F; ...&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;func&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; main&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;() {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    config&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; :=&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; Config&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;        DBHost&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; os&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;Getenv&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;DB_HOST&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;        DBPort&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 3306&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    repo&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; :=&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; NewUserRepository&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;config&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;    &#x2F;&#x2F; ...&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;code&gt;UserRepository&lt;&#x2F;code&gt;が何に依存しているかが&lt;code&gt;NewUserRepository&lt;&#x2F;code&gt;の引数として明示されています。テスト時には異なる&lt;code&gt;Config&lt;&#x2F;code&gt;を渡すだけで済みます。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;まとめ&quot;&gt;まとめ&lt;&#x2F;h2&gt;
&lt;p&gt;本記事では、GoFの残り13パターンのうち2つを検討しました。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Iterator&lt;&#x2F;strong&gt; — 言語機能として吸収され、パターンとして意識する必要がなくなった&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Singleton&lt;&#x2F;strong&gt; — OOPの副作用とは無関係に、グローバル状態という本質的な問題から非推奨となった。依存性の注入（DI）がより優れた解法として確立されている&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;次回は、残る11のパターンがなぜ現代でも有用なのかを分析し、シリーズ全体の結論としてデザインパターンの本質的価値を考察します。&lt;&#x2F;p&gt;
&lt;section class=&quot;footnotes&quot;&gt;
&lt;ol class=&quot;footnotes-list&quot;&gt;
&lt;li id=&quot;fn-affiliate&quot;&gt;
&lt;p&gt;このリンクはAmazonアソシエイトのリンクです。 &lt;a href=&quot;#fr-affiliate-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;&#x2F;section&gt;
</content>
        <summary type="html">GoFの残り13パターンのうち、Iteratorは言語機能として吸収され、Singletonは現代の設計手法により非推奨となりました。それぞれの経緯をGo言語のコードとともに検討します。</summary>
        </entry><entry xml:lang="en">
        <title>GoFデザインパターンは現代でも有用か(2) — Go言語で不要になったパターン</title>
        <published>2026-04-01T10:00:00+09:00</published>
        <updated>2026-04-01T10:00:00+09:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2026/04/gof-design-patterns/02-unnecessary-patterns/" type="text/html"/>
        <id>https://codedchords.dev/blog/2026/04/gof-design-patterns/02-unnecessary-patterns/</id>
        
            <content type="html">&lt;!-- textlint-disable --&gt;
&lt;img
  src=&quot;https:&amp;#x2F;&amp;#x2F;codedchords.dev&amp;#x2F;blog&amp;#x2F;2026&amp;#x2F;04&amp;#x2F;gof-design-patterns&amp;#x2F;02-unnecessary-patterns&amp;#x2F;cover.webp?h=395d88df7f249e0311f1&quot;
  alt=&quot;Cover&quot; width=&quot;1792&quot; height=&quot;1024&quot; loading=&quot;lazy&quot;
&#x2F;&gt;&lt;!-- textlint-enable --&gt;
&lt;details&gt;
&lt;summary&gt;Table of Contents&lt;&#x2F;summary&gt;
&lt;!-- toc --&gt;
&lt;&#x2F;details&gt;
&lt;h2 id=&quot;前回の振り返り&quot;&gt;前回の振り返り&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;codedchords.dev&#x2F;blog&#x2F;2026&#x2F;04&#x2F;gof-design-patterns&#x2F;01-paradigm-shift&#x2F;&quot;&gt;前回&lt;&#x2F;a&gt;は、OOPが手続き型プログラミングからのパラダイムシフトとして登場した経緯、OOPの設計ノウハウを体系化したGoFデザインパターンが広く受け入れられた歴史、そして現代ではOOPの中核を意図的に排除したGo言語が登場したことを振り返りました。&lt;&#x2F;p&gt;
&lt;p&gt;Go言語の設計方針は、OOPとの対比で次の3点に集約されます。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;クラス継承を排除し、合成（composition）と暗黙的インターフェースで代替した&lt;&#x2F;li&gt;
&lt;li&gt;参照セマンティクスではなく値セマンティクスをデフォルトにした&lt;&#x2F;li&gt;
&lt;li&gt;振る舞いもオブジェクトに包む制約を廃し、第一級関数とチャネル&#x2F;ゴルーチンで直接扱えるようにした&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;この設計方針を踏まえて、GoFの23パターンをGo言語の視点から再検討してみましょう。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;「クラス継承」の副作用への処方箋だったパターン&quot;&gt;「クラス継承」の副作用への処方箋だったパターン&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;OOP「クラス継承」がもたらしたもの&quot;&gt;OOP「クラス継承」がもたらしたもの&lt;&#x2F;h3&gt;
&lt;p&gt;ソフトウェアの保守性と拡張性を担保するために、「&lt;strong&gt;既存のコードを変更せずに機能を拡張する&lt;&#x2F;strong&gt;」という原則 — 開放閉鎖原則（Open-Closed Principle）が求められてきました。手続き型言語では、機能を追加するたび既存コードへ分岐を追加するしかなく、変更が既存の動作を壊すリスクが常にありました。OOPはこの課題に対して、&lt;strong&gt;クラス継承&lt;&#x2F;strong&gt;という新たなメカニズムで解決を図りました。基底クラスを定義し、サブクラスで振る舞いをオーバーライドすることで、既存コードに手を加えずに機能を拡張します。これがOOPの基本戦略でした。&lt;&#x2F;p&gt;
&lt;p&gt;しかし、継承自体が新たな問題を生みます。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;脆弱な基底クラス問題&lt;&#x2F;strong&gt; — 親クラスを変更すると、全てのサブクラスに影響が波及する。「変更せずに拡張」したかったのに、親を変えた瞬間に子が壊れる&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;密結合&lt;&#x2F;strong&gt; — サブクラスは親クラスの実装詳細に依存する。拡張のつもりが、内部実装への依存を生む&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;単一継承の制約&lt;&#x2F;strong&gt; — Java等では1つのクラスしか継承できない。拡張の方向が1軸に制限される&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;深い階層の可読性低下&lt;&#x2F;strong&gt; — 継承が何段にも重なると、実際の振る舞いを追うのが困難になる&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;デザインパターンは、この継承の副作用を管理するための処方箋でした。以下のパターンが該当します。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Template Method&lt;&#x2F;strong&gt; — 親クラスでアルゴリズムの骨格を定義し、サブクラスで具体的なステップをオーバーライドする。継承による骨格と詳細の分離を体系化したもの&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Factory Method&lt;&#x2F;strong&gt; — オブジェクトの生成をサブクラスに委ねることで、生成ロジックの拡張を継承で管理する&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Abstract Factory&lt;&#x2F;strong&gt; — 関連するオブジェクト群の生成を抽象クラスの階層で管理する&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Bridge&lt;&#x2F;strong&gt; — 抽象クラスの階層と実装クラスの階層を分離し、それぞれ独立して拡張可能にする。継承階層を2つに分けることで拡張の柔軟性を確保する&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;これらはいずれも「継承をどう使えば安全に拡張できるか」を体系化したものであり、継承というメカニズムが前提にあって初めて意味を持つパターンです。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;Go言語の解法_—_継承のない拡張性&quot;&gt;Go言語の解法 — 継承のない拡張性&lt;&#x2F;h3&gt;
&lt;p&gt;Go言語はこの問題の連鎖に対して、根本的に異なる道を選びました。クラス継承を排除し、&lt;strong&gt;暗黙的インターフェースと合成（composition）&lt;&#x2F;strong&gt; によって開放閉鎖原則を実現しています。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;暗黙的インターフェース&lt;&#x2F;strong&gt; — &lt;code&gt;implements&lt;&#x2F;code&gt;の宣言が不要で、メソッドのシグネチャが合致すれば自動的にインターフェースを満たす。既存の型に触れることなく、新しいインターフェースへ適合させられる。つまり、既存コードを変更せず新しい抽象に対応できる&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;合成（composition）&lt;&#x2F;strong&gt; — 構造体の埋め込み（embedding）により、既存の型を変更せずに振る舞いを追加できる。継承のような親子の密結合が生まれず、拡張しても既存コードへの影響がない&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;継承の副作用が存在しないため、その副作用を管理するためのデザインパターンも必要ありません。これらのパターンが「Go言語では成立しない」のは、解決すべき問題が言語設計の時点で回避されているからです。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;「参照セマンティクス」を補完するパターン&quot;&gt;「参照セマンティクス」を補完するパターン&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;「参照セマンティクス」がもたらしたもの&quot;&gt;「参照セマンティクス」がもたらしたもの&lt;&#x2F;h3&gt;
&lt;p&gt;OOPの多くの言語は参照セマンティクス&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-reference-semantics-1&quot;&gt;&lt;a href=&quot;#fn-reference-semantics&quot;&gt;1&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;を採用しています。これはOOPの設計思想と深く結びついています。OOPでは「このオブジェクトとあのオブジェクトは同一か」というオブジェクトの同一性（identity）が重要であり、基底クラスの参照を通じて派生クラスのメソッドを呼び出すポリモーフィズムも参照なしでは成立しません。参照セマンティクスはOOPにとって必然的な選択でした。&lt;&#x2F;p&gt;
&lt;p&gt;しかし、参照セマンティクスは副作用も伴います。変数に代入してもオブジェクト自体はコピーされず、同じ実体を指す参照が増えるだけです。C言語でいえば、すべての変数がポインタ経由でデータにアクセスしているようなものであり、手続き型言語のグローバル変数と同様に「どこで変更されるか追跡できない」という課題をオブジェクト単位で持ち込んでしまいます。この性質がオブジェクトの複製や状態の保存・復元を厄介な問題にし、それを解決するためのデザインパターンが必要でした。&lt;&#x2F;p&gt;
&lt;p&gt;Go言語は値セマンティクス&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-value-semantics-1&quot;&gt;&lt;a href=&quot;#fn-value-semantics&quot;&gt;2&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;を採用しています。OOPを捨てたことで、参照をデフォルトにする必要がなくなりました。値セマンティクスは並行処理の安全性（ゴルーチン間でコピーを渡せば共有状態が減る）と予測可能性（代入の振る舞いが明示的で単純）をもたらします。参照が必要な場合は、ポインタで明示的に指定します。&lt;&#x2F;p&gt;
&lt;p&gt;この「&lt;strong&gt;デフォルトは値、参照が必要なら明示せよ&lt;&#x2F;strong&gt;」という設計方針は、Go言語独自のものではありません。Rustはムーブセマンティクスをデフォルトとし参照は&lt;code&gt;&amp;amp;&lt;&#x2F;code&gt;で明示します。Swiftは構造体（struct）を値型とし、Appleは構造体の使用を推奨しています。OOP以降の現代的な言語設計に共通するトレンドです。&lt;&#x2F;p&gt;
&lt;p&gt;この値セマンティクスにより、以下のパターンが解決しようとした問題は大幅に簡素化されます。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;既存オブジェクトをコピーして新しいオブジェクトを生成する&quot;&gt;既存オブジェクトをコピーして新しいオブジェクトを生成する&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Prototype&lt;&#x2F;strong&gt; — 参照セマンティクスの世界では、オブジェクトの「正しいコピー」を作ること自体が設計上の課題であり、Clone()メソッドの実装やプロトタイプ登録といった仕組みが必要だった&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Go言語では、構造体の代入がそのままコピーです。&lt;code&gt;b := a&lt;&#x2F;code&gt;と書けばフィールドがすべて複製されます。ポインタを含む構造体の深いコピーには注意が必要ですが、パターンとしての仕組みは不要です。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;オブジェクトの内部状態を保存し復元する&quot;&gt;オブジェクトの内部状態を保存し復元する&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Memento&lt;&#x2F;strong&gt; — Originator（状態を持つ対象）、Memento（保存された状態）、Caretaker（保存を管理する者）の3者構造で、カプセル化を壊さずに状態を保存・復元する仕組みを実現していた&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Go言語では、構造体をそのままコピーすればスナップショットになります。&lt;code&gt;saved := currentState&lt;&#x2F;code&gt;で保存、&lt;code&gt;currentState = saved&lt;&#x2F;code&gt;で復元です。OOPが苦心した「カプセル化を維持しつつ状態を外部に保存する」という問題自体が、値セマンティクスによって解消されています。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;「振る舞い」をオブジェクトに包む制約への処方箋だったパターン&quot;&gt;「振る舞い」をオブジェクトに包む制約への処方箋だったパターン&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;「すべてがオブジェクト」がもたらしたもの&quot;&gt;「すべてがオブジェクト」がもたらしたもの&lt;&#x2F;h3&gt;
&lt;p&gt;OOPの「すべてがオブジェクト」という原則は、データと振る舞いを一体化することで、手続き型言語のようにデータと関数がバラバラに散らばる問題を解消しました。統一的なモデルで設計を語れることは、OOPの大きな功績です。&lt;&#x2F;p&gt;
&lt;p&gt;しかし、ソフトウェアでは要件の変化や文脈の違いに応じて、データはそのままに処理だけを差し替える場面が頻繁に発生します。同じデータを異なる基準でソートしたい、同じリクエスト処理を本番ではDB接続、テストではモックに差し替えたい、といった場面です。OOPの「すべてがオブジェクト」という原則は、このような振る舞いだけを渡したい場面でも、それをオブジェクト（クラス）に包むことを強制しました。関数を1つ渡したいだけなのに、インターフェースを定義し、具象クラスを実装し、そのインスタンスを生成する。この儀式が、以下のパターンを生みました。&lt;&#x2F;p&gt;
&lt;p&gt;Go言語では、第一級関数であり、チャネルとゴルーチンが言語に組み込まれています。振る舞いをオブジェクトに包む必要がなくなったことで、これらのパターンは不要になりました。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;アルゴリズムを動的に切り替える&quot;&gt;アルゴリズムを動的に切り替える&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Strategy&lt;&#x2F;strong&gt; — Strategyインターフェースを定義し、各アルゴリズムを具象クラスとして実装し、コンテキストオブジェクトに注入するという手順が必要だった&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Javaでは、ソート順を差し替えるだけでもインターフェースと具象クラスが必要です。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;java&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;&#x2F;&#x2F; Strategyインターフェース&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-modifier&quot;&gt;interface&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; SortStrategy&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;    void&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; sort&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;int&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[]&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt; data&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;&#x2F;&#x2F; 具象クラス：昇順&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-modifier&quot;&gt;class&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; AscendingSort&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-modifier z-implements&quot;&gt; implements&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-other z-inherited-class&quot;&gt; SortStrategy&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-modifier z-storage z-type&quot;&gt;    public void&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; sort&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;int&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[]&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt; data&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;) {&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt; &#x2F;* 昇順ソート *&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;&#x2F;&#x2F; 具象クラス：降順&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-modifier&quot;&gt;class&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; DescendingSort&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-modifier z-implements&quot;&gt; implements&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-other z-inherited-class&quot;&gt; SortStrategy&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-modifier z-storage z-type&quot;&gt;    public void&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; sort&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;int&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[]&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt; data&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;) {&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt; &#x2F;* 降順ソート *&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;&#x2F;&#x2F; コンテキストクラス&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-modifier&quot;&gt;class&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; Sorter&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-modifier z-storage z-type&quot;&gt;    private SortStrategy&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; strategy&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;    Sorter&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;SortStrategy&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt; strategy&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable z-language z-this&quot;&gt;        this&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;strategy&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; strategy&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;    void&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; execute&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;int&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[]&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt; data&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;        strategy&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;sort&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;data&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;&#x2F;&#x2F; 使用側&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;Sorter&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; s&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; new&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; Sorter&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;new&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; AscendingSort&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;());&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;s&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;execute&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;data&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Go言語では第一級関数をサポートしています。ソート処理を行う関数が、ソート順を関数として受け取るだけで済みます。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;go&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;&#x2F;&#x2F; ソート順を関数として受け取る。クラスもインターフェースも不要&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;func&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; executeSort&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt;data&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; []&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;int&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt; less&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; func&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt;i&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt; j&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt; int&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt; bool&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    sort&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;Slice&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;data&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; less&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;&#x2F;&#x2F; 関数を変数に代入するだけで「具象クラス」に相当する&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;ascending&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; :=&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; func&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt;i&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt; j&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt; int&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt; bool&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; {&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; return&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; data&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;i&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; &amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; data&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;j&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;] }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;descending&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; :=&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; func&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt;i&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt; j&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt; int&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt; bool&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; {&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; return&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; data&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;i&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; &amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; data&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;j&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;] }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;&#x2F;&#x2F; 使用側&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;executeSort&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;data&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; ascending&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Javaでは振る舞いを差し替えるためにインターフェース、具象クラス、コンテキストクラスの3層が必要でした。Go言語では関数を引数として渡すだけで同じことが実現できます。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;操作の実行・取り消し・キューイングを可能にする&quot;&gt;操作の実行・取り消し・キューイングを可能にする&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Command&lt;&#x2F;strong&gt; — リクエストをオブジェクトとしてカプセル化し、操作をデータとして扱えるようにしていた&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Go言語では関数とクロージャがCommandオブジェクトの役割を果たします。関数をスライスに格納してキューイングする、クロージャで実行時のコンテキストを閉じ込める、といった操作が言語機能として自然に書けます。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;データ構造に新しい操作を追加する&quot;&gt;データ構造に新しい操作を追加する&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Visitor&lt;&#x2F;strong&gt; — データ構造に対する操作を追加したいとき、操作をVisitorオブジェクトに包み、ダブルディスパッチ（accept&#x2F;visit）で呼び出す必要があった&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Go言語ではtype switchにより、型に応じた処理分岐を直接記述できます。操作をオブジェクトに包む必要も、ダブルディスパッチのような間接的な仕組みも不要です。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;オブジェクトの状態変化を通知する&quot;&gt;オブジェクトの状態変化を通知する&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Observer&lt;&#x2F;strong&gt; — Subject&#x2F;Observerインターフェースを定義し、登録・通知・解除のメカニズムを実装する必要があった&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;エラーイベントが発生したら、ログ出力とアラート送信の2つの処理に通知する例で対比してみます。
Javaでは、Observerインターフェースの定義、Subject（EventSource）への登録メカニズム、通知ループの実装が必要です。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;java&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;&#x2F;&#x2F; Observerインターフェース&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-modifier&quot;&gt;interface&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; Observer&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;    void&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; update&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;String&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt; event&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;&#x2F;&#x2F; 具象クラス：ログ出力&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-modifier&quot;&gt;class&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; LogObserver&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-modifier z-implements&quot;&gt; implements&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-other z-inherited-class&quot;&gt; Observer&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-modifier z-storage z-type&quot;&gt;    public void&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; update&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;String&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt; event&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;        System&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;out&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;println&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;Logger: &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; +&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; event&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;&#x2F;&#x2F; 具象クラス：アラート送信&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-modifier&quot;&gt;class&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; AlertObserver&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-modifier z-implements&quot;&gt; implements&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-other z-inherited-class&quot;&gt; Observer&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-modifier z-storage z-type&quot;&gt;    public void&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; update&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;String&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt; event&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;        sendAlert&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;event&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;&#x2F;&#x2F; Subject：Observerの登録と通知を管理する&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-modifier&quot;&gt;class&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; EventSource&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-modifier z-storage z-type&quot;&gt;    private List&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;Observer&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; observers&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-storage z-type&quot;&gt; new ArrayList&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;lt;&amp;gt;();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;    void&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; addObserver&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;Observer&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt; o&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;) {&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; observers&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;add&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;o&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;); }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;    void&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; notifyObservers&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;String&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt; event&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;        for&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; (&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;Observer&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; o&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; :&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; observers&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;            o&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;update&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;event&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;        }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;&#x2F;&#x2F; 使用側：Observerを登録し、イベントを通知する&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;EventSource&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; source&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; new&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; EventSource&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;source&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;addObserver&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;new&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; LogObserver&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;());&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;source&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;addObserver&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;new&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; AlertObserver&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;());&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;source&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;notifyObservers&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;error occurred&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Go言語では、チャネルとゴルーチンがこの役割を担います。Observerをチャネルのスライスで管理し、動的に登録できます。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;go&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;&#x2F;&#x2F; チャネル：Observerへの通知経路をスライスで管理&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;observers&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; :=&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; []&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-storage z-type&quot;&gt;chan string&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;{}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;&#x2F;&#x2F; Observer登録：チャネルを作成し、ゴルーチンで待ち受ける&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;logCh&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; :=&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; make&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-storage z-type&quot;&gt;chan string&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;observers&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; append&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;observers&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; logCh&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;go func&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;() {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;    for&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; event&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; :=&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; range&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; logCh&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;        fmt&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;Println&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;Logger:&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; event&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;}()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;alertCh&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; :=&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; make&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-storage z-type&quot;&gt;chan string&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;observers&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; append&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;observers&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; alertCh&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;go func&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;() {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;    for&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; event&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; :=&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; range&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; alertCh&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;        sendAlert&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;event&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;}()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;&#x2F;&#x2F; 全Observerに通知&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;for&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; _&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; ch&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; :=&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; range&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; observers&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    ch&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; &amp;lt;-&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;error occurred&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Javaではインターフェース定義、登録メカニズム、通知ループが必要でした。Go言語ではチャネルが型安全な通知メカニズムとなり、ゴルーチンが通知を受け取る側の並行処理を自然に表現します。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;まとめ&quot;&gt;まとめ&lt;&#x2F;h2&gt;
&lt;p&gt;本記事では、Go言語の3つの設計方針がGoFのデザインパターンをどのように不要にしたかを確認しました。&lt;&#x2F;p&gt;
&lt;!-- textlint-disable --&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Go言語の設計方針&lt;&#x2F;th&gt;&lt;th&gt;不要になったパターン&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;クラス継承を排除し、合成と暗黙的インターフェースで代替&lt;&#x2F;td&gt;&lt;td&gt;Template Method, Factory Method, Abstract Factory, Bridge&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;参照セマンティクスではなく値セマンティクスをデフォルトに&lt;&#x2F;td&gt;&lt;td&gt;Prototype, Memento&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;振る舞いもオブジェクトに包む制約を廃し、第一級関数とチャネル&#x2F;ゴルーチンで直接扱えるように&lt;&#x2F;td&gt;&lt;td&gt;Strategy, Command, Visitor, Observer&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;!-- textlint-enable --&gt;
&lt;p&gt;これらのパターンが不要になったのは、パターンの設計思想が間違っていたからではありません。OOPの制約の中で生まれた処方箋が、制約そのものを取り除いたGo言語では必要なくなった、ということです。&lt;&#x2F;p&gt;
&lt;p&gt;しかし、GoFの23パターンすべてがOOPの制約に起因するわけではありません。次回は、言語やパラダイムに依存しない普遍的な設計原則として、現代でも有用なパターンを検討します。&lt;&#x2F;p&gt;
&lt;section class=&quot;footnotes&quot;&gt;
&lt;ol class=&quot;footnotes-list&quot;&gt;
&lt;li id=&quot;fn-reference-semantics&quot;&gt;
&lt;p&gt;参照セマンティクス（reference semantics）とは、変数への代入がオブジェクトの参照（ポインタ）をコピーする振る舞いのこと。代入先を変更すると、元のオブジェクトも影響を受ける。Java、Pythonなどが採用している（C#はクラスが参照型、構造体が値型と区別している）。 &lt;a href=&quot;#fr-reference-semantics-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li id=&quot;fn-value-semantics&quot;&gt;
&lt;p&gt;値セマンティクス（value semantics）とは、変数への代入がデータそのものをコピーする振る舞いのこと。代入先を変更しても、元のデータには影響しない。Go言語の構造体やC言語の構造体が採用している。 &lt;a href=&quot;#fr-value-semantics-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;&#x2F;section&gt;
</content>
        <summary type="html">GoFの23パターンをGo言語の視点から再検討します。クラス継承の副作用への処方箋だったもの、参照セマンティクスを補完するもの、振る舞いをオブジェクトに包む制約への処方箋だったもの。</summary>
        </entry><entry xml:lang="en">
        <title>GoFデザインパターンは現代でも有用か(1) — OOPのパラダイムシフトとGoFの誕生</title>
        <published>2026-04-01T05:58:00+09:00</published>
        <updated>2026-04-01T05:58:00+09:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2026/04/gof-design-patterns/01-paradigm-shift/" type="text/html"/>
        <id>https://codedchords.dev/blog/2026/04/gof-design-patterns/01-paradigm-shift/</id>
        
            <content type="html">&lt;!-- textlint-disable --&gt;
&lt;img
  src=&quot;https:&amp;#x2F;&amp;#x2F;codedchords.dev&amp;#x2F;blog&amp;#x2F;2026&amp;#x2F;04&amp;#x2F;gof-design-patterns&amp;#x2F;01-paradigm-shift&amp;#x2F;cover.webp?h=3fe18a08fd8d2440cfce&quot;
  alt=&quot;Cover&quot; width=&quot;1792&quot; height=&quot;1024&quot; loading=&quot;lazy&quot;
&#x2F;&gt;&lt;!-- textlint-enable --&gt;
&lt;details&gt;
&lt;summary&gt;Table of Contents&lt;&#x2F;summary&gt;
&lt;!-- toc --&gt;
&lt;&#x2F;details&gt;
&lt;p&gt;自宅の本棚の整理をしていて、『&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;amzn.to&#x2F;4bW36Po&quot;&gt;Java言語で学ぶデザインパターン入門&lt;&#x2F;a&gt;第2版』(結城浩著)&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-affiliate-1&quot;&gt;&lt;a href=&quot;#fn-affiliate&quot;&gt;1&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;を見つけました。「今どきJava言語かね」
と思い調べてみると、5年程前に第3版が出版されていました。&lt;&#x2F;p&gt;
&lt;p&gt;「そう言えば、今どきの言語でデザインパターンってどうなんだ？」と考察していました。&lt;&#x2F;p&gt;
&lt;p&gt;本記事では、なぜ脱オブジェクト指向プログラミング（以降、OOP）のパラダイムシフトが起きたのか、そしてGoFの23のデザインパターンをGo言語ではどう扱うべきかを検討し考察してみます。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;手続き型プログラミングの限界&quot;&gt;手続き型プログラミングの限界&lt;&#x2F;h2&gt;
&lt;p&gt;1960年代から1980年代にかけて、ソフトウェア開発の主流は手続き型プログラミングでした。C言語やFortranに代表されるこのパラダイムでは、データと手続き（関数）は分離して管理されます。プログラムの規模が小さいうちは問題になりませんが、規模が大きくなるにつれて、どの関数がどのデータを操作するのかを追跡することが困難になっていきました。&lt;&#x2F;p&gt;
&lt;p&gt;当時仕事ではメインフレーム中心で私の職場ではPL&#x2F;Iを使っていましたが、規模を大きくしないためかバッチ指向のデザインが好まれていました。
そのため1つ1つは短いプログラムですが、内部ではグローバル変数への依存、関数間の暗黙的なデータ受け渡しが行われていました。そして短いプログラムでも、結局ファイルを介してバッチストリーム全体がストレージ共有をしているので、変更の影響範囲が予測できないという問題が深刻化しました。&lt;&#x2F;p&gt;
&lt;p&gt;やがて、1990年代に入るとWindows&#x2F;Macintoshに加えて、IBMのOS&#x2F;2、SunやHPのワークステーションが業務で使えるレベルのシステムとなり、「ダウンサイジング」の波が業務アプリケーションの世界にも押し寄せました。この問題はさらに致命的になりました。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;OOPというパラダイムシフト&quot;&gt;OOPというパラダイムシフト&lt;&#x2F;h2&gt;
&lt;p&gt;OOP（オブジェクト指向プログラミング）は、手続き型プログラミングにおけるデータと手続きの分離がもたらす複雑さに対するパラダイムシフトでした。データとそれを操作する手続きを「オブジェクト」として一体化し、カプセル化によって内部状態を保護する。オブジェクト間はメッセージパッシングで協調し、継承によってコードを再利用する。Simula（1967年）で芽生え、Smalltalk（1980年）で確立されたこの思想は、1990年代にC++やJavaの普及とともに主流となりました。&lt;&#x2F;p&gt;
&lt;p&gt;OOPの普及を決定づけたのは、ダウンサイジングがもたらしたGUIクライアントの台頭です。Windowsの普及により、ソフトウェアはウィンドウ、ボタン、メニューといった視覚的な部品で構成されるようになりました。これらのUI部品は、状態を持ち、イベントに応答し、階層的に組み合わされる — まさにオブジェクトとしてモデル化するのに適した対象でした。GUIツールキットはOOPの実践的な成功例となり、OOPこそがソフトウェア開発の正しいアプローチであるという認識を広めました。&lt;&#x2F;p&gt;
&lt;p&gt;一方でOOPは、カプセル化、継承、ポリモーフィズムという新しい概念を持ち込んだために、手続き型言語で機能分割しかやって来なかった当時の開発者たちに「OOPではどうコードを書くべきなのか」と悩ませることになりました。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;GoFデザインパターンの誕生&quot;&gt;GoFデザインパターンの誕生&lt;&#x2F;h2&gt;
&lt;p&gt;この状況の中で、1994年にGoF（Gang of Four）&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-gof-1&quot;&gt;&lt;a href=&quot;#fn-gof&quot;&gt;2&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;が『&lt;strong&gt;Design Patterns: Elements of Reusable Object-Oriented Software&lt;&#x2F;strong&gt;』を出版しました。GoFはオブジェクト指向設計で繰り返し現れる23のパターンを、生成（Creational）5種、構造（Structural）7種、振舞（Behavioral）11種の3つに分類して体系化しました。これらのパターンは、当時の開発者にとって「OOPでよいコードを書くためのお手本」として受け入れられました。&lt;&#x2F;p&gt;
&lt;!-- textlint-disable --&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;分類&lt;&#x2F;th&gt;&lt;th&gt;パターン名&lt;&#x2F;th&gt;&lt;th&gt;概要&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;Creational（生成）&lt;&#x2F;td&gt;&lt;td&gt;Abstract Factory&lt;&#x2F;td&gt;&lt;td&gt;オブジェクトを具象クラスを指定せずに生成&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;&#x2F;td&gt;&lt;td&gt;Builder&lt;&#x2F;td&gt;&lt;td&gt;複雑なオブジェクトを抽象化し段階的に生成&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;&#x2F;td&gt;&lt;td&gt;Factory Method&lt;&#x2F;td&gt;&lt;td&gt;オブジェクトの生成をサブクラスに委ねる&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;&#x2F;td&gt;&lt;td&gt;Prototype&lt;&#x2F;td&gt;&lt;td&gt;既存オブジェクトをコピーし新オブジェクトを生成&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;&#x2F;td&gt;&lt;td&gt;Singleton&lt;&#x2F;td&gt;&lt;td&gt;インスタンスが1つだけであることを保証&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Structural（構造）&lt;&#x2F;td&gt;&lt;td&gt;Adapter&lt;&#x2F;td&gt;&lt;td&gt;互換性のないインターフェースのクラス同士を接続&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;&#x2F;td&gt;&lt;td&gt;Bridge&lt;&#x2F;td&gt;&lt;td&gt;抽象部分と実装部分を分離。独立に変更可能&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;&#x2F;td&gt;&lt;td&gt;Composite&lt;&#x2F;td&gt;&lt;td&gt;ツリー構造により個別オブジェクトと合成を同一視&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;&#x2F;td&gt;&lt;td&gt;Decorator&lt;&#x2F;td&gt;&lt;td&gt;オブジェクトに動的に新しい責務を追加&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;&#x2F;td&gt;&lt;td&gt;Facade&lt;&#x2F;td&gt;&lt;td&gt;サブシステムの複雑なインターフェースの統一的な窓口&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;&#x2F;td&gt;&lt;td&gt;Flyweight&lt;&#x2F;td&gt;&lt;td&gt;多数の細粒度オブジェクトを共有してメモリ使用量削減&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;&#x2F;td&gt;&lt;td&gt;Proxy&lt;&#x2F;td&gt;&lt;td&gt;他のオブジェクトへのアクセス制御する代理オブジェクト&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Behavioral（振舞）&lt;&#x2F;td&gt;&lt;td&gt;Chain of Responsibility&lt;&#x2F;td&gt;&lt;td&gt;リクエスト処理するオブジェクト連鎖を構成し処理を委譲&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;&#x2F;td&gt;&lt;td&gt;Command&lt;&#x2F;td&gt;&lt;td&gt;リクエストをオブジェクト化し、実行取消や再実行を可能&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;&#x2F;td&gt;&lt;td&gt;Interpreter&lt;&#x2F;td&gt;&lt;td&gt;言語の文法を定義し解釈するインタプリタを提供&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;&#x2F;td&gt;&lt;td&gt;Iterator&lt;&#x2F;td&gt;&lt;td&gt;内部構造を公開せずに、集合要素へアクセスする方法&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;&#x2F;td&gt;&lt;td&gt;Mediator&lt;&#x2F;td&gt;&lt;td&gt;オブジェクト間の相互作用を仲介者に集約し疎結合&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;&#x2F;td&gt;&lt;td&gt;Memento&lt;&#x2F;td&gt;&lt;td&gt;オブジェクトの内部状態を保存し、復元可能に&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;&#x2F;td&gt;&lt;td&gt;Observer&lt;&#x2F;td&gt;&lt;td&gt;状態変化を他のオブジェクトに自動的に通知&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;&#x2F;td&gt;&lt;td&gt;State&lt;&#x2F;td&gt;&lt;td&gt;オブジェクトの内部状態に応じて振舞を変更する&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;&#x2F;td&gt;&lt;td&gt;Strategy&lt;&#x2F;td&gt;&lt;td&gt;アルゴリズムをカプセル化し、実行時に切り替え可能&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;&#x2F;td&gt;&lt;td&gt;Template Method&lt;&#x2F;td&gt;&lt;td&gt;アルゴリズムの骨格を定義、ステップをサブクラスに委譲&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;&#x2F;td&gt;&lt;td&gt;Visitor&lt;&#x2F;td&gt;&lt;td&gt;データ構造と処理を分離し、新しい処理を追加しやすくする&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;!-- textlint-enable --&gt;
&lt;h2 id=&quot;新たなパラダイムシフト_—_なぜGoogleはOOPを捨てたのか&quot;&gt;新たなパラダイムシフト — なぜGoogleはOOPを捨てたのか&lt;&#x2F;h2&gt;
&lt;p&gt;GoFが出版されてから10年以上が経った2007年、Googleの中で新しい言語の設計が始まりました&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-go-creators-1&quot;&gt;&lt;a href=&quot;#fn-go-creators&quot;&gt;3&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;。&lt;&#x2F;p&gt;
&lt;p&gt;新言語の開発に踏み切った背景には、GoogleのC++コードベースの深刻な問題がありました。数百万行規模のコードではビルドに数十分から数時間を要し、複雑な依存関係の管理は開発者の大きな負担になっていました。C++の持つ豊富な機能 — テンプレート、多重継承、演算子オーバーロード — は、大規模なチーム開発においてコードの可読性を損ない、新しいメンバーの参入障壁を高めていました。&lt;&#x2F;p&gt;
&lt;p&gt;Go言語の設計者たちが出した答えは、複雑さを足すのではなく引くことでした。2009年にオープンソースとして公開されたGo言語は、OOPの中核を意図的に排除し、代わりに以下の設計方針を採用しています。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;クラス継承を排除し、合成（composition）と暗黙的インターフェースで代替した&lt;&#x2F;li&gt;
&lt;li&gt;参照セマンティクスではなく値セマンティクスをデフォルトにした&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-semantics-1&quot;&gt;&lt;a href=&quot;#fn-semantics&quot;&gt;4&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;&lt;&#x2F;li&gt;
&lt;li&gt;振る舞いもオブジェクトに包む制約を廃し、第一級関数とチャネル&#x2F;ゴルーチンで直接扱えるようにした&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;確かに近年はC++&#x2F;JavaのようなOOPでなく、次のような言語を選択するシーンが私自身も増えています。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Python — クラスも書けるが、関数だけでも十分に実用的&lt;&#x2F;li&gt;
&lt;li&gt;Ruby — 実は言語設計は徹底的にOOP（全てがオブジェクト）。ただし実際の使われ方は柔軟&lt;&#x2F;li&gt;
&lt;li&gt;JavaScript — そもそもクラスベースではなくプロトタイプベース。ES6のclassは後付けの構文糖&lt;&#x2F;li&gt;
&lt;li&gt;TypeScript — JavaScriptに型を足したもの。OOPと関数型のどちらでも自然に書ける&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;これらはOOPですがマルチパラダイムで、OOPじゃないパラダイムでもコードが書けます。&lt;&#x2F;p&gt;
&lt;p&gt;では、Go言語はOOPなのでしょうか。Go言語にはメソッドやインターフェースがあり、カプセル化も実現できます。しかし、クラスや継承はありません。Go言語のFAQでは「Yes and no」と回答されています。Go言語はOOPの有用な部分（カプセル化、多態性）を残しつつ、複雑さの元凶（継承、型階層）を切り捨てた言語です。上記のような言語からさらにOOPを薄めたものと言えます。&lt;&#x2F;p&gt;
&lt;p&gt;Go言語の登場は、OOPに続く新たなパラダイムシフトの象徴です。&lt;&#x2F;p&gt;
&lt;p&gt;ここで1つの疑問が浮かびます。GoFのデザインパターンは「OOPでよいコードを書くためのお手本」として受け入れられました。しかし、Go言語はそのOOPの中核 — 継承、型階層、参照セマンティクス — を排除しています。もしGoFのパターンが本当にOOPの仕組みに依存したものであるなら、Go言語ではそれらのパターンは成立しないはずです。逆に、パターンの中に言語やパラダイムに依存しない普遍的な設計原則が含まれているなら、Go言語でも形を変えて生き残るはずです。&lt;&#x2F;p&gt;
&lt;p&gt;次回は、GoFの23のパターンをGo言語の視点から1つずつ再検討し、この仮説を検証していきます。&lt;&#x2F;p&gt;
&lt;section class=&quot;footnotes&quot;&gt;
&lt;ol class=&quot;footnotes-list&quot;&gt;
&lt;li id=&quot;fn-affiliate&quot;&gt;
&lt;p&gt;このリンクはAmazonアソシエイトのリンクです。 &lt;a href=&quot;#fr-affiliate-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li id=&quot;fn-gof&quot;&gt;
&lt;p&gt;Gang of Four（GoF）は、Erich Gamma、Richard Helm、Ralph Johnson、John Vlissidesの4人の通称。 &lt;a href=&quot;#fr-gof-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li id=&quot;fn-go-creators&quot;&gt;
&lt;p&gt;主導したのはRob Pike（UNIXやPlan 9の開発者）、Ken Thompson（UNIXの共同開発者）、Robert Griesemerの3人です。 &lt;a href=&quot;#fr-go-creators-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li id=&quot;fn-semantics&quot;&gt;
&lt;p&gt;参照セマンティクス（reference semantics）とは、変数への代入がオブジェクトの参照（ポインタ）をコピーする振る舞いのこと。値セマンティクス（value semantics）とは、変数への代入がデータそのものをコピーする振る舞いのこと。 &lt;a href=&quot;#fr-semantics-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;&#x2F;section&gt;
</content>
        <summary type="html">手続き型からOOPへのパラダイムシフト、そしてOOPの不完全さから生まれたGoFデザインパターン。なぜGoogleはOOPを捨ててGo言語を作ったのか。その背景を整理します。</summary>
        </entry><entry xml:lang="en">
        <title>無料で始める Cloudflare セキュリティ対策</title>
        <published>2026-03-23T00:00:00+00:00</published>
        <updated>2026-03-23T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2026/03/cloudflare-free-security/" type="text/html"/>
        <id>https://codedchords.dev/blog/2026/03/cloudflare-free-security/</id>
        
            <content type="html">&lt;!-- textlint-disable --&gt;
&lt;img
  src=&quot;https:&amp;#x2F;&amp;#x2F;codedchords.dev&amp;#x2F;blog&amp;#x2F;2026&amp;#x2F;03&amp;#x2F;cloudflare-free-security&amp;#x2F;cover.webp?h=9bfc915254c8cd5bf47d&quot;
  alt=&quot;Cover&quot; width=&quot;1792&quot; height=&quot;1024&quot; loading=&quot;lazy&quot;
&#x2F;&gt;&lt;!-- textlint-enable --&gt;
&lt;span id=&quot;continue-reading&quot;&gt;&lt;&#x2F;span&gt;&lt;h2 id=&quot;公開翌日に何が起きたか&quot;&gt;公開翌日に何が起きたか&lt;&#x2F;h2&gt;
&lt;p&gt;先日の記事で紹介した生成AIを使った&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;ask.codedchords.dev&quot;&gt;Ask&lt;&#x2F;a&gt; ページを公開した翌日、CloudflareのObservabilityを確認したところ、攻撃と思われるリクエストが並んでいました。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;GET &#x2F;.env&lt;&#x2F;code&gt; — 環境変数ファイルの探索&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;&#x2F;checkout&lt;&#x2F;code&gt;, &lt;code&gt;&#x2F;plans&lt;&#x2F;code&gt;, &lt;code&gt;&#x2F;signup&lt;&#x2F;code&gt; — SaaS系パスの総当たり&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;&#x2F;wp-login&lt;&#x2F;code&gt;, &lt;code&gt;&#x2F;wp-admin&lt;&#x2F;code&gt;, &lt;code&gt;&#x2F;xmlrpc.php&lt;&#x2F;code&gt; — WordPress管理画面の探索&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;&#x2F;api&#x2F;v1&#x2F;stripe&#x2F;config.js&lt;&#x2F;code&gt;, &lt;code&gt;&#x2F;api&#x2F;v2&#x2F;payment&#x2F;keys.js&lt;&#x2F;code&gt; — 決済APIの設定ファイル探索（Stripeはオンライン決済プラットフォーム）&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;config.php&lt;&#x2F;code&gt;, &lt;code&gt;&#x2F;api&#x2F;system&#x2F;info&lt;&#x2F;code&gt; — サーバー情報の収集&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;主にWordPressなどのCMSやStripeなどの決済サービスを狙ったスキャンです。静的サイト＋Workerという構成なのでそんなサービスは乗せていないのですが。公開されているエンドポイントに対してよく狙われる既知のパスを片っ端から叩いているのでしょう。&lt;&#x2F;p&gt;
&lt;p&gt;実害はありませんが、放置するのも気持ちが悪いですし、Workers AIのNeuronsを無駄に消費されるのは避けたいところです。Cloudflareの無料プランのセキュリティ機能で対策しました。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;対策1:_Bot_Fight_Mode&quot;&gt;対策1: Bot Fight Mode&lt;&#x2F;h2&gt;
&lt;p&gt;最も手軽な対策です。Cloudflareダッシュボードの &lt;strong&gt;Security &amp;gt; Bots&lt;&#x2F;strong&gt; から、ワンクリックで有効化できます。&lt;&#x2F;p&gt;
&lt;p&gt;Bot Fight ModeはCloudflareが持つボットの行動パターンデータベースを使い、自動化されたアクセスを検出して計算コストの高いチャレンジを返します。検索エンジンのクローラーなど検証済みの正当なボットは通過させる仕組みです。&lt;&#x2F;p&gt;
&lt;p&gt;設定はON&#x2F;OFFだけで、細かなチューニングは有料プラン（Super Bot Fight Mode）の機能になります。それでも、汎用的なスキャンボットの大半はこれで弾けます。&lt;&#x2F;p&gt;
&lt;p&gt;注意点として、Bot Fight Modeは外部サービスからのWebhookやRSSリーダーのフィード取得など、正当な自動アクセスもブロックする場合があります。無料プランではWAFルールによるバイパス（Skip）ができないため、これらのサービスに影響が出た場合はBot Fight Mode自体を無効にする必要があります。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;対策2:_WAF_カスタムルール&quot;&gt;対策2: WAF カスタムルール&lt;&#x2F;h2&gt;
&lt;p&gt;Bot Fight Modeをすり抜けるアクセスに対しては、WAF（Web Application Firewall）のカスタムルールで対処します。無料プランでは5つまでルールを作成できます。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;ルール1:_許可パスの制限（ホワイトリスト）&quot;&gt;ルール1: 許可パスの制限（ホワイトリスト）&lt;&#x2F;h3&gt;
&lt;p&gt;最も効果が高いルールを最優先に配置します。ask.codedchords.devは &lt;code&gt;&#x2F;&lt;&#x2F;code&gt;（フロントエンド）と &lt;code&gt;&#x2F;api&#x2F;&lt;&#x2F;code&gt;（Workers API）しか使わないので、それ以外を全てブロックします。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;plain&quot; data-name=&quot;Expression&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;(http.host eq &amp;quot;ask.codedchords.dev&amp;quot;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;and not (http.request.uri.path eq &amp;quot;&#x2F;&amp;quot; or http.request.uri.path contains &amp;quot;&#x2F;api&#x2F;&amp;quot;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Actionは &lt;strong&gt;Block&lt;&#x2F;strong&gt;、Place atは &lt;strong&gt;First&lt;&#x2F;strong&gt; に設定します。&lt;&#x2F;p&gt;
&lt;p&gt;「正当なパスだけを許可する」ホワイトリスト方式なので、攻撃者がどんなパスを試してもすり抜けられません。ただし、対象サイトの構成を把握している必要があります。新しいパスを追加した際にルールの更新を忘れると自分自身のコンテンツがブロックされるため、サイト構成を変更したらルールも見直してください。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;ルール2:_スキャンパスの遮断（ブラックリスト）&quot;&gt;ルール2: スキャンパスの遮断（ブラックリスト）&lt;&#x2F;h3&gt;
&lt;p&gt;ルール1はaskサブドメイン限定なので、ドメイン全体に適用する汎用ルールも設定します。WordPressやphpMyAdminなど、よく狙われるパスへのアクセスを一括でブロックします。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Security &amp;gt; Security rules &amp;gt; Create rule&lt;&#x2F;strong&gt; から、以下のExpressionを設定します。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;plain&quot; data-name=&quot;Expression&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;(http.request.uri.path contains &amp;quot;.env&amp;quot;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;or (http.request.uri.path contains &amp;quot;wp-login&amp;quot;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;or (http.request.uri.path contains &amp;quot;wp-admin&amp;quot;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;or (http.request.uri.path contains &amp;quot;xmlrpc.php&amp;quot;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;or (http.request.uri.path contains &amp;quot;phpmyadmin&amp;quot;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;or (http.request.uri.path contains &amp;quot;wp-content&amp;quot;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;or (http.request.uri.path contains &amp;quot;wp-includes&amp;quot;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Actionは &lt;strong&gt;Block&lt;&#x2F;strong&gt; です。&lt;&#x2F;p&gt;
&lt;p&gt;このルールはサイトの構成に依存しないため、Cloudflareで管理しているドメイン全体に適用できます。WordPressを使っていないサイトであれば、デメリットはありません。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;対策3:_Rate_Limiting&quot;&gt;対策3: Rate Limiting&lt;&#x2F;h2&gt;
&lt;p&gt;Bot Fight ModeとWAFルールを通過したリクエストに対する最後の砦です。同一IPからの過剰なリクエストを制限します。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Security &amp;gt; Security rules &amp;gt; Rate limiting rules&lt;&#x2F;strong&gt; から設定します。&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;項目&lt;&#x2F;th&gt;&lt;th&gt;設定値&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;対象&lt;&#x2F;td&gt;&lt;td&gt;&lt;code&gt;http.host eq &quot;ask.codedchords.dev&quot;&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;判定基準&lt;&#x2F;td&gt;&lt;td&gt;IP&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;レート&lt;&#x2F;td&gt;&lt;td&gt;10リクエスト &#x2F; 10秒&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Action&lt;&#x2F;td&gt;&lt;td&gt;Block（10秒間）&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;無料プランではRate Limitingルールは1つまで、ブロック期間は最大10秒という制約があります。大規模な攻撃には有料プランのRate Limiting（より長いブロック期間、より多くのルール）が必要ですが、スキャンボット対策としては十分です。上記の設定値は一例です。ページ内のリソース数や想定されるアクセスパターンに応じて調整してください。&lt;&#x2F;p&gt;
&lt;p&gt;なお、今回はWorkers側にも &lt;code&gt;&#x2F;api&#x2F;ask&lt;&#x2F;code&gt; エンドポイントに対して同一IP 60秒間10リクエストの制限を入れています。CloudflareのRate Limitingはインフラ層での粗いフィルタリング、Workers側はアプリケーション層での細かな制御という役割分担です。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;3層防御の全体像&quot;&gt;3層防御の全体像&lt;&#x2F;h2&gt;
&lt;p&gt;設定した対策を整理します。&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;レイヤー&lt;&#x2F;th&gt;&lt;th&gt;対策&lt;&#x2F;th&gt;&lt;th&gt;役割&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;第1層&lt;&#x2F;td&gt;&lt;td&gt;Bot Fight Mode&lt;&#x2F;td&gt;&lt;td&gt;既知のボットパターンを自動検出&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;第2層&lt;&#x2F;td&gt;&lt;td&gt;WAF カスタムルール&lt;&#x2F;td&gt;&lt;td&gt;不正なパス・不要なパスを遮断&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;第3層&lt;&#x2F;td&gt;&lt;td&gt;Rate Limiting&lt;&#x2F;td&gt;&lt;td&gt;過剰なリクエストを制限&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;いずれもCloudflareの無料プランで利用でき、設定はダッシュボードからの操作だけで完結します。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;まとめ&quot;&gt;まとめ&lt;&#x2F;h2&gt;
&lt;p&gt;これらの設定を適用した直後から、Observability上でスキャン系のリクエストがブロックされていることを確認できました。Workers AIのNeuronsが無駄に消費されることもなくなっています。&lt;&#x2F;p&gt;
&lt;p&gt;個人サイトであっても、公開すればスキャンボットは来ます。「小規模だから狙われない」ということはありません。ボットは規模を問わず、見つけたエンドポイントを片っ端から叩きます。&lt;&#x2F;p&gt;
&lt;p&gt;Cloudflareを使っているなら、無料プランの範囲でもBot Fight Mode、WAFカスタムルール、Rate Limitingの3つを設定するだけで、大半の自動化されたスキャンは防げます。設定にかかる時間は10分程度です。特にWorkers AIやAPIエンドポイントを公開している場合は、不要なリクエストによるリソース消費を防ぐためにも早めの対策をおすすめします。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;References&quot;&gt;References&lt;&#x2F;h2&gt;
&lt;!-- textlint-disable --&gt;
&lt;div class=&quot;references&quot;&gt;
    &lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;developers.cloudflare.com&#x2F;bots&#x2F;get-started&#x2F;free&#x2F;&quot;&gt;Cloudflare&lt;&#x2F;a&gt;. &quot;Bot Fight Mode&quot;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;developers.cloudflare.com&#x2F;waf&#x2F;custom-rules&#x2F;&quot;&gt;Cloudflare&lt;&#x2F;a&gt;. &quot;Custom rules&quot;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;developers.cloudflare.com&#x2F;waf&#x2F;rate-limiting-rules&#x2F;&quot;&gt;Cloudflare&lt;&#x2F;a&gt;. &quot;Rate limiting rules&quot;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;

&lt;&#x2F;div&gt;
&lt;!-- textlint-enable --&gt;
</content>
        <summary type="html">個人ブログにAI Chat機能を追加した翌日、スキャンボットの集中アクセスを確認しました。Cloudflareの無料プランだけで実施できるBot Fight Mode、WAFカスタムルール、Rate Limitingの3つの対策を紹介します。</summary>
        </entry><entry xml:lang="en">
        <title>Cloudflare Workers AI + Vectorize で RAG</title>
        <published>2026-03-20T00:00:01+09:00</published>
        <updated>2026-05-07T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2026/03/ask-my-digital-double/" type="text/html"/>
        <id>https://codedchords.dev/blog/2026/03/ask-my-digital-double/</id>
        
            <content type="html">&lt;!-- textlint-disable --&gt;
&lt;img
  src=&quot;https:&amp;#x2F;&amp;#x2F;codedchords.dev&amp;#x2F;blog&amp;#x2F;2026&amp;#x2F;03&amp;#x2F;ask-my-digital-double&amp;#x2F;cover.webp?h=1c0e8f975b65a3d29155&quot;
  alt=&quot;Cover&quot; width=&quot;1792&quot; height=&quot;1024&quot; loading=&quot;lazy&quot;
&#x2F;&gt;&lt;!-- textlint-enable --&gt;
&lt;details&gt;
&lt;summary&gt;Table of Contents&lt;&#x2F;summary&gt;
&lt;!-- toc --&gt;
&lt;&#x2F;details&gt;
&lt;span id=&quot;continue-reading&quot;&gt;&lt;&#x2F;span&gt;&lt;h2 id=&quot;何を作ったのか&quot;&gt;何を作ったのか&lt;&#x2F;h2&gt;
&lt;p&gt;このブログのナビゲーションに「ask」というメニューを追加しました。
私のデジタル分身(bot)に質問できるページが表示されます。質問を入力すると、ブログ記事の内容を踏まえて私っぽい回答を返します。&lt;&#x2F;p&gt;
&lt;p&gt;ブログに書いてある話題はもちろん、書いていない話題についても「私ならこう答えるだろう」という推測で回答を生成します。
ただし、たかだか個人ブログの文書量ですから大した学習量ではないため、平気で嘘をつきます。それも含めて楽しんでもらえればと思います。&lt;&#x2F;p&gt;
&lt;p&gt;たとえば、こんな質問を投げてみます。&lt;&#x2F;p&gt;
&lt;!-- textlint-disable --&gt;
&lt;div class=&quot;admonition tip&quot;&gt;
    &lt;div class=&quot;admonition-icon admonition-icon-tip&quot;&gt;&lt;&#x2F;div&gt;
    &lt;div class=&quot;admonition-content&quot;&gt;
        &lt;strong class=&quot;admonition-title&quot;&gt;Q&amp;A の例&lt;&#x2F;strong&gt;
        &lt;p&gt;&lt;strong&gt;Q:&lt;&#x2F;strong&gt; CIOも設置せず、IT Governanceの取り組みを行なわない理事長が「生成AIを導入したい」と言っています。どうすべきですか？&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;A:&lt;&#x2F;strong&gt; その理事長に、生成AIの導入が「新しいシステムの導入」と違うことを説明する必要があります。生成AIは、組織の判断の中枢に組み込まれ、自社固有の文脈で動く必要があります。そのためには、IT部門だけでなく、業務部門の理解と協力が必要です。
また、生成AIの導入には、データの整備、セキュリティの確保、コンプライアンスの確保などの準備が必要です。CIOを設置せず、IT Governanceの取り組みを行なわない組織では、これらの準備を十分に整えることが難しいでしょう。（以下、省略）&lt;&#x2F;p&gt;

    &lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;!-- textlint-enable --&gt;
&lt;p&gt;私が答えそうな回答を返してきました。ブログ記事の内容をベースにしつつ、ペルソナの設定に基づいた回答を生成しています。&lt;&#x2F;p&gt;
&lt;p&gt;ソースコードはGitHubで公開しています。&lt;&#x2F;p&gt;
&lt;!-- textlint-disable --&gt;
&lt;iframe class=&quot;hatenablogcard&quot; src=&quot;https:&#x2F;&#x2F;hatenablog-parts.com&#x2F;embed?url=https:&amp;#x2F;&amp;#x2F;github.com&amp;#x2F;yostos&amp;#x2F;yostos-persona&quot; width=&quot;100%&quot; height=&quot;155&quot; frameborder=&quot;0&quot; scrolling=&quot;no&quot; loading=&quot;lazy&quot;&gt;&lt;&#x2F;iframe&gt;
&lt;!-- textlint-enable --&gt;
&lt;h2 id=&quot;動機&quot;&gt;動機&lt;&#x2F;h2&gt;
&lt;p&gt;仕事を終えて職場を変えることになったとき、同僚が「質問できなくなるので、あなたのbotがあればいいのに」と言ってくれました。ありがたい話です。真に受けました。&lt;&#x2F;p&gt;
&lt;p&gt;もう1つの動機は、せっかくブログをCloudflare Pagesに移行したのでWorkers AIも試してみようという技術的な興味です。Workers AI、Vectorize、Workersを組み合わせたRAGシステムを自分で組んでみたかったですし、構築過程がそのままブログのネタになるのも都合が良いと思いました。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;アーキテクチャ&quot;&gt;アーキテクチャ&lt;&#x2F;h2&gt;
&lt;p&gt;処理フローはシンプルなRAGパターンです。&lt;&#x2F;p&gt;
&lt;p&gt;まず事前処理として、ブログ記事をVectorizeに投入しておきます。&lt;&#x2F;p&gt;
&lt;!-- textlint-disable --&gt;


&lt;noscript&gt;
    &lt;strong&gt;⚠️ JavaScript is required to render the diagram.&lt;&#x2F;strong&gt;
&lt;&#x2F;noscript&gt;
&lt;pre class=&quot;mermaid invertible-image&quot;&gt;
    graph LR
Articles[ブログ記事&lt;br&gt;Markdown]--&gt; Parse[front matter解析&lt;br&gt;+ セクション分割]--&gt; EMB1[BGE-M3&lt;br&gt;embedding]--&gt; V[(Vectorize)]
&lt;&#x2F;pre&gt;
&lt;!-- textlint-enable --&gt;
&lt;p&gt;質問時は、入力をベクトル化して類似チャンクを検索し、ペルソナ設定と合わせてLLMに渡します。&lt;&#x2F;p&gt;
&lt;!-- textlint-disable --&gt;


&lt;noscript&gt;
    &lt;strong&gt;⚠️ JavaScript is required to render the diagram.&lt;&#x2F;strong&gt;
&lt;&#x2F;noscript&gt;
&lt;pre class=&quot;mermaid invertible-image&quot;&gt;
    graph LR
Q[質問]--&gt; EMB2[BGE-M3&lt;br&gt;embedding]--&gt; V[(Vectorize)]
V --&gt;|類似チャンク| LLM[Llama 3.3 70B]
Persona[ペルソナ設定]--&gt; LLM
LLM --&gt; A[回答 +&lt;br&gt;参考記事リンク]
&lt;&#x2F;pre&gt;
&lt;!-- textlint-enable --&gt;
&lt;ol&gt;
&lt;li&gt;ユーザーが質問を入力&lt;&#x2F;li&gt;
&lt;li&gt;WorkersがBGE-M3で質問をベクトル化&lt;&#x2F;li&gt;
&lt;li&gt;Vectorizeで類似チャンクを検索（上位5件、スコア閾値0.3）&lt;&#x2F;li&gt;
&lt;li&gt;システムプロンプト（ペルソナ設定）＋ 取得したチャンク ＋ 質問をLlama 3.3 70Bに渡す&lt;&#x2F;li&gt;
&lt;li&gt;回答テキスト＋参考記事リンクをフロントエンドに返す&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;使用しているCloudflareサービスはWorkers、Workers AI（EmbeddingとLLM）、Vectorizeの3つだけです。フロントエンドはWorkersのAssets機能で配信しています。フレームワークは使わず、素のHTML&#x2F;CSS&#x2F;JSで構築しました。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;モデル選定&quot;&gt;モデル選定&lt;&#x2F;h2&gt;
&lt;p&gt;EmbeddingモデルはBGE-M3（&lt;code&gt;@cf&#x2F;baai&#x2F;bge-m3&lt;&#x2F;code&gt;）を採用しました。BAAI開発の多言語対応モデルで、出力は1024次元です。日本語と英語が混在するブログ記事に対応できることが決め手でした。当初はPLaMo-Embedding-1Bを検討しましたが、出力が2048次元でVectorizeの上限（1536次元）を超えるため断念しています。&lt;&#x2F;p&gt;
&lt;p&gt;LLMはLlama 3.3 70B Instruct FP8 Fast（&lt;code&gt;@cf&#x2F;meta&#x2F;llama-3.3-70b-instruct-fp8-fast&lt;&#x2F;code&gt;）です。128Kトークンのコンテキストウィンドウを持ち、日本語でのペルソナ付き回答生成は概ね良好です。中国語文字の混入が発生すると既知の問題として上がっています。今回は、システムプロンプトで抑制しています。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;事前処理:_ナレッジベースの構築&quot;&gt;事前処理: ナレッジベースの構築&lt;&#x2F;h2&gt;
&lt;p&gt;ブログのMarkdownファイル群をナレッジとして使用しており、これらを解析して事前にVectorizeする処理スクリプト(ingest)が行う処理は以下の通りです。&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;記事のファイルパス、front matterからslug、title、date、tagsを抽出し、本文を見出し（&lt;code&gt;##&lt;&#x2F;code&gt;）単位でセクション分割&lt;&#x2F;li&gt;
&lt;li&gt;各チャンクにメタデータ（ファイルパス、slug、title、section、URL）を付与&lt;&#x2F;li&gt;
&lt;li&gt;BGE-M3でベクトル化してVectorizeにアップサート&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;差分検出にはマニフェストファイル（slug → MD5ハッシュのマッピング）を使い、変更のあった記事のみ再処理します。初回ingestでは286記事を処理しました。Vectorizeのメタデータ上限（10,240 bytes）対策として、チャンク本文を8,000 bytesに切り詰めています。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;質問(Request)対応:_Workers_AI_のコード&quot;&gt;質問(Request)対応: Workers AI のコード&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;Vectorize処理&quot;&gt;Vectorize処理&lt;&#x2F;h3&gt;
&lt;p&gt;Workers AIの特徴は &lt;code&gt;env.AI.run()&lt;&#x2F;code&gt; というバインディング呼び出しです。APIキーの管理もSDKのインストールも不要で、&lt;code&gt;wrangler.toml&lt;&#x2F;code&gt; の &lt;code&gt;[ai]&lt;&#x2F;code&gt; セクションに &lt;code&gt;binding = &quot;AI&quot;&lt;&#x2F;code&gt; と書くだけで使えます。&lt;&#x2F;p&gt;
&lt;p&gt;RAGの検索部分（rag.ts）を丸ごと載せます。Embedding生成からVectorize検索まで、これだけで完結しています。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;typescript&quot; data-name=&quot;src&#x2F;worker&#x2F;rag.ts&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;import type&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; {&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt; Env&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; }&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; from&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;.&#x2F;types&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-storage z-type&quot;&gt;export interface&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; RetrievedChunk&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable z-object z-property&quot;&gt;  text&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-primitive&quot;&gt; string&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable z-object z-property&quot;&gt;  meta&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable z-object z-property&quot;&gt;    slug&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-primitive&quot;&gt; string&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable z-object z-property&quot;&gt;    title&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-primitive&quot;&gt; string&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable z-object z-property&quot;&gt;    section&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-primitive&quot;&gt; string&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable z-object z-property&quot;&gt;    url&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-primitive&quot;&gt; string&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;  };&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable z-object z-property&quot;&gt;  score&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-primitive&quot;&gt; number&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;const&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt; SCORE_THRESHOLD&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 0.3&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;const&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt; TOP_K&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 5&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-storage z-modifier z-storage z-type&quot;&gt;export async function&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; retrieveChunks&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt;  question&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-primitive&quot;&gt; string&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt;  env&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; Env&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; Promise&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type z-meta z-type&quot;&gt;RetrievedChunk[]&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;  &#x2F;&#x2F; Embed the question&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;  const&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt; embeddingResult&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; await&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; env&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-constant&quot;&gt;AI&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;run&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;@cf&#x2F;baai&#x2F;bge-m3&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;, {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    text&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-variable z-other z-readwrite&quot;&gt; [question]&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;  }&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;  const&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt; queryVector&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; embeddingResult&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-property z-ts z-source&quot;&gt;data[&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;0&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;]&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;  &#x2F;&#x2F; Search Vectorize&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;  const&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt; results&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; await&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; env&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-constant&quot;&gt;VECTORIZE&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;query&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-variable z-other z-readwrite&quot;&gt;(queryVector&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;, {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    topK&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt; TOP_K&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    returnValues&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language z-boolean&quot;&gt; false&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    returnMetadata&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;all&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;  }&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;  &#x2F;&#x2F; Filter by score threshold and map to chunks&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;  return&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; results&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-property z-ts&quot;&gt;matches&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;    .&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;filter&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt;m&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-function z-arrow z-ts&quot;&gt; =&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; m&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-property z-ts&quot;&gt;score&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; &amp;gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts z-source&quot;&gt; SCORE_THRESHOLD)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;    .&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;map&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt;m&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-function z-arrow z-ts&quot;&gt; =&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; (&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;      text&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; (m&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;metadata&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;?.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-property z-ts&quot;&gt;text&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-support z-type z-primitive&quot;&gt; as string&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; ||&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;quot;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;      meta&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;        slug&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; (m&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;metadata&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;?.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-property z-ts&quot;&gt;slug&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-support z-type z-primitive&quot;&gt; as string&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; ||&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;quot;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;        title&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; (m&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;metadata&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;?.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-property z-ts&quot;&gt;title&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-support z-type z-primitive&quot;&gt; as string&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; ||&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;quot;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;        section&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; (m&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;metadata&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;?.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-property z-ts&quot;&gt;section&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-support z-type z-primitive&quot;&gt; as string&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; ||&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;quot;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;        url&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; (m&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;metadata&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;?.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-property z-ts&quot;&gt;url&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-support z-type z-primitive&quot;&gt; as string&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; ||&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;quot;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;      },&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;      score&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; m&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-property z-ts&quot;&gt;score&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    }&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;))&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;LLM呼び出し&quot;&gt;LLM呼び出し&lt;&#x2F;h3&gt;
&lt;p&gt;LLMの呼び出しも同じパターンです。&lt;code&gt;env.AI.run()&lt;&#x2F;code&gt; にモデル名とメッセージを渡すだけで回答が返ってきます。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;typescript&quot; data-name=&quot;src&#x2F;worker&#x2F;index.ts（抜粋）&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;const&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt; llmResult&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; await&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; env&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-constant&quot;&gt;AI&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;run&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;  &amp;quot;@cf&#x2F;meta&#x2F;llama-3.3-70b-instruct-fp8-fast&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;  {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    messages&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; [&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;      {&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; role&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;system&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; content&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt; systemPrompt&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; },&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;      {&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; role&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;user&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; content&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt; question&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; },&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    ]&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    max_tokens&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 512&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;  }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;const&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt; answer&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-variable z-other z-readwrite&quot;&gt; (llmResult&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; as&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; {&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-object z-property&quot;&gt; response&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;?:&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-primitive&quot;&gt; string&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; }&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-property z-ts&quot;&gt;response&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;  ||&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;回答を生成できませんでした。&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;外部APIを叩いている感覚がなく、Workersの中でAIを呼んでいるだけという体験は新鮮です。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;ペルソナ設定&quot;&gt;ペルソナ設定&lt;&#x2F;h3&gt;
&lt;p&gt;コードの &lt;code&gt;systemPrompt&lt;&#x2F;code&gt; として渡しているのがペルソナ設定です。回答は私のキャラクタ設定に基づいて生成されます。元IBM&#x2F;AWSのエンジニア、ギター愛好家、CLIツール開発が趣味といったプロフィールに加えて、口調や回答スタイルも定義しています。敬語ベースで、好きな話題には熱量が上がり、知らないことでもぺらぺら喋るという設定です。こうしてみると、オタクそのものですね。&lt;&#x2F;p&gt;
&lt;p&gt;回答スタイルとして、簡潔に答えるだけでなく、ときどき脱線したり問い返したりするような振る舞いも仕込んでいます。200〜300文字程度を目安にしていますが、実際の挙動はモデル次第です。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;コスト&quot;&gt;コスト&lt;&#x2F;h2&gt;
&lt;p&gt;個人ブログのQ&amp;amp;Aという用途なので、非機能要件は「1日数十件の質問を無料枠内で処理できること」に設定しています。&lt;&#x2F;p&gt;
&lt;p&gt;Workers AIの課金単位はNeuronsです。1リクエストあたりの消費量を見積もります。&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;処理&lt;&#x2F;th&gt;&lt;th&gt;モデル&lt;&#x2F;th&gt;&lt;th style=&quot;text-align: right&quot;&gt;トークン数（概算）&lt;&#x2F;th&gt;&lt;th style=&quot;text-align: right&quot;&gt;Neurons&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;Embedding（質問文）&lt;&#x2F;td&gt;&lt;td&gt;BGE-M3&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;50 入力&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;0.05&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;LLM 入力（プロンプト＋チャンク＋質問）&lt;&#x2F;td&gt;&lt;td&gt;Llama 3.3 70B&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;2,000 入力&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;53&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;LLM 出力（回答生成）&lt;&#x2F;td&gt;&lt;td&gt;Llama 3.3 70B&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;512 出力&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;105&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;合計&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;td&gt;&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;&lt;strong&gt;約160&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;Workers AIの無料枠は10,000 Neurons&#x2F;日なので、&lt;strong&gt;約60リクエスト&#x2F;日&lt;&#x2F;strong&gt;が上限になります。&lt;&#x2F;p&gt;
&lt;p&gt;Vectorizeも無料枠に十分収まります。&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;リソース&lt;&#x2F;th&gt;&lt;th style=&quot;text-align: right&quot;&gt;使用量&lt;&#x2F;th&gt;&lt;th style=&quot;text-align: right&quot;&gt;無料枠&lt;&#x2F;th&gt;&lt;th style=&quot;text-align: right&quot;&gt;消費率&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;格納次元数（286記事 × 1,024次元）&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;約29万&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;500万&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;6%&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;クエリ次元数&#x2F;月&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;数千&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;3,000万&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: right&quot;&gt;0.1%未満&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;超過した場合はWorkers Paidプラン（月$5）で$0.011&#x2F;1,000 Neuronsの従量課金になりますが、現在の利用量では発生しない見込みです。仮に想定の倍（120リクエスト&#x2F;日）が30日続いたとしても、超過分は月約288,000 Neuronsで約$3.2、プラン基本料と合わせて月$8程度です。&lt;&#x2F;p&gt;
&lt;p&gt;悪用防止として、KVベースでIPあたり60秒間10リクエストのレート制限をかけています。単一IPからの過剰なリクエストは抑制できますが、分散アクセスに対しては無力なので、無料枠の維持を保証するものではありません。個人ブログの自然なトラフィックであれば問題ない想定です。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;今後の課題&quot;&gt;今後の課題&lt;&#x2F;h2&gt;
&lt;p&gt;現時点で把握している課題は、BGE-M3の日本語検索精度、チャンク分割の粒度、LLMのmax_tokens最適値（回答品質とコストのバランス）、同一質問に対するキャッシュによる重複推論の回避です。&lt;&#x2F;p&gt;
&lt;p&gt;いずれの改善も、実際にどんな質問が来るかわからない段階では手の打ちようがありません。精度を上げるには実際の質問パターンに基づいた評価用クエリが必要で、つまりフィードバックループを回す必要があります。ただし、面白半分で作ったお遊びですし、質問内容を保持するのはプライバシーの観点で望ましくないため、質問内容のロギングは行っていません。一方で、ブログ記事が増えればナレッジベースが厚くなり、検索精度は自然と改善していく可能性があります。&lt;&#x2F;p&gt;
&lt;p&gt;完璧なものを作ってから公開するよりも、動くものを出して改善していくほうが性に合っています。質問を投げてみて、変な回答が返ってきたら、それはそれで面白いと思ってください。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;References&quot;&gt;References&lt;&#x2F;h2&gt;
&lt;!-- textlint-disable --&gt;
&lt;div class=&quot;references&quot;&gt;
    &lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;developers.cloudflare.com&#x2F;workers-ai&#x2F;&quot;&gt;Cloudflare&lt;&#x2F;a&gt;. &quot;Workers AI&quot;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;developers.cloudflare.com&#x2F;vectorize&#x2F;&quot;&gt;Cloudflare&lt;&#x2F;a&gt;. &quot;Vectorize&quot;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;huggingface.co&#x2F;BAAI&#x2F;bge-m3&quot;&gt;BAAI&lt;&#x2F;a&gt;. &quot;BGE-M3&quot;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;

&lt;&#x2F;div&gt;
&lt;!-- textlint-enable --&gt;
</content>
        <summary type="html">ブログ記事をナレッジベースにして、著者のペルソナで質問に答えるAI Q&amp;Aページを Cloudflare Workers AI と Vectorize で構築しました。BGE-M3 による日本語 embedding、Llama 3.3 70B によるペルソナ付き回答生成、差分 ingest パイプラインまで、Cloudflare スタックだけで完結しています。</summary>
        </entry><entry xml:lang="en">
        <title>ブログ記事をBlueskyに自動投稿する — GitHub Actions + AT Protocol</title>
        <published>2026-03-18T00:00:00+00:00</published>
        <updated>2026-03-18T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2026/03/bluesky-auto-post/" type="text/html"/>
        <id>https://codedchords.dev/blog/2026/03/bluesky-auto-post/</id>
        
            <content type="html">&lt;!-- textlint-disable --&gt;
&lt;img
  src=&quot;https:&amp;#x2F;&amp;#x2F;codedchords.dev&amp;#x2F;blog&amp;#x2F;2026&amp;#x2F;03&amp;#x2F;bluesky-auto-post&amp;#x2F;cover.webp?h=28408c7b912f8c80fa6a&quot;
  alt=&quot;Cover&quot; width=&quot;1792&quot; height=&quot;1024&quot; loading=&quot;lazy&quot;
&#x2F;&gt;&lt;!-- textlint-enable --&gt;
&lt;span id=&quot;continue-reading&quot;&gt;&lt;&#x2F;span&gt;&lt;h2 id=&quot;なぜBlueskyなのか&quot;&gt;なぜBlueskyなのか&lt;&#x2F;h2&gt;
&lt;p&gt;Blueskyは、AT Protocolという分散型プロトコル上に構築されたSNSです。ブログの告知先としてSNSを選ぶなら、X（旧Twitter）が最初の候補に挙がるかもしれません。しかし、XのAPIは2023年に有料化され、無料プランでは月1,500件の投稿しかできません。自動投稿の仕組みを維持するために月額の課金が必要になります。rate limitも厳しく、突然の仕様変更で動かなくなるリスクも無視できません。そもそも、a chaotic messと化したプラットフォームに技術記事の告知を流す意味があるのかという根本的な疑問もあります。&lt;&#x2F;p&gt;
&lt;p&gt;一方、BlueskyのAT Protocol APIは完全に無料で、認証もアプリパスワード1つで済みます。プロトコル仕様が公開されており、&lt;code&gt;curl&lt;&#x2F;code&gt; で直接叩ける素朴さがあります。個人ブログの告知先としては、APIの安定性とコストの両面でBlueskyに優位性があると判断しました。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;手動投稿の煩わしさ&quot;&gt;手動投稿の煩わしさ&lt;&#x2F;h2&gt;
&lt;p&gt;ブログ記事を書き上げてpushした後、Blueskyを開いてURLを貼り、説明文を添えて投稿する。この手作業は1分で終わりますが、毎回やるのは面倒です。忘れることもあります。&lt;&#x2F;p&gt;
&lt;p&gt;このブログはZolaで生成し、Cloudflare Pagesでホスティングしています。記事の公開は &lt;code&gt;git push origin main&lt;&#x2F;code&gt; で完了します。であれば、Blueskyへの告知もこのpushをトリガーにして自動化するのが自然な流れです。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;なぜGitHub_Actionsなのか&quot;&gt;なぜGitHub Actionsなのか&lt;&#x2F;h2&gt;
&lt;p&gt;自動投稿の実現方法について、いくつか検討してみました。&lt;&#x2F;p&gt;
&lt;p&gt;1.Cloudflare Worker + Deploy Hook&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;インフラをCloudflareで統一できる利点があるが、「新規記事かどうか」の判定にKV等の状態管理が必要になる。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;ローカルのフック（Claude Code Hookなど）&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;ul&gt;
&lt;li&gt;シンプルだが、別マシンからの投稿時に動作しない。また、GitHub Actionの完了との同期が面倒である。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;IFTTT&#x2F;Zapier等のSaaS&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;ul&gt;
&lt;li&gt;簡単だが、RSSベースのため遅延が発生する。また、プライバシーの懸念もある。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;結局、GitHub Actionsへ組み込むことにしました。&lt;&#x2F;p&gt;
&lt;p&gt;GitHub Actionsを選んだ決め手は、&lt;code&gt;git diff&lt;&#x2F;code&gt; が使えることです。&lt;code&gt;git diff --name-status HEAD~1 HEAD&lt;&#x2F;code&gt; の出力で &lt;code&gt;A&lt;&#x2F;code&gt;（Added）ステータスかつ &lt;code&gt;content&#x2F;**&#x2F;index.md&lt;&#x2F;code&gt; に一致するファイルを検出すれば、新規記事だけを正確に判別できます。更新や削除では発動しません。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;仕組みの全体像&quot;&gt;仕組みの全体像&lt;&#x2F;h2&gt;
&lt;p&gt;処理フローはシンプルです。&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;mainブランチへのpushでワークフローが起動&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;git diff&lt;&#x2F;code&gt; で新規記事（&lt;code&gt;A&lt;&#x2F;code&gt; ステータスの &lt;code&gt;index.md&lt;&#x2F;code&gt;）を検出&lt;&#x2F;li&gt;
&lt;li&gt;frontmatter（TOML形式）からtitle、description、tagsを抽出&lt;&#x2F;li&gt;
&lt;li&gt;Bluesky AT Protocol APIで認証&lt;&#x2F;li&gt;
&lt;li&gt;OGP画像を &lt;code&gt;com.atproto.repo.uploadBlob&lt;&#x2F;code&gt; でアップロード&lt;&#x2F;li&gt;
&lt;li&gt;リンクカード（サムネイル付き）のポストを作成&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;ワークフローとスクリプトの2ファイル構成です。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;ワークフロー&quot;&gt;ワークフロー&lt;&#x2F;h2&gt;
&lt;p&gt;ワークフローは新規記事の検出と、スクリプトの呼び出しに責務を限定しています。&lt;&#x2F;p&gt;
&lt;!-- textlint-disable --&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;yaml&quot; data-name=&quot;.github&#x2F;workflows&#x2F;bluesky-post.yml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;name&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; Post to Bluesky&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-constant z-language z-boolean&quot;&gt;on&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;  push&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;    branches&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;main&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;    paths&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;#39;content&#x2F;**&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;jobs&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;  post&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;    runs-on&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; ubuntu-latest&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;    steps&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;      -&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt; uses&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; actions&#x2F;checkout@v6&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;        with&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;          fetch-depth&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 2&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;      -&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt; name&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; Detect new articles&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;        id&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; detect&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;        run&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; |&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;          new_articles=$(git diff --name-status HEAD~1 HEAD \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;            | grep &amp;#39;^A&amp;#39; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;            | awk &amp;#39;{print $2}&amp;#39; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;            | grep &amp;#39;content&#x2F;.*&#x2F;index\.md$&amp;#39; || true)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;          if [ -z &amp;quot;$new_articles&amp;quot; ]; then&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;            echo &amp;quot;No new articles found&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;            echo &amp;quot;has_new=false&amp;quot; &amp;gt;&amp;gt; &amp;quot;$GITHUB_OUTPUT&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;          else&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;            echo &amp;quot;New articles found:&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;            echo &amp;quot;$new_articles&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;            {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;              echo &amp;quot;articles&amp;lt;&amp;lt;EOF&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;              echo &amp;quot;$new_articles&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;              echo &amp;quot;EOF&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;            } &amp;gt;&amp;gt; &amp;quot;$GITHUB_OUTPUT&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;            echo &amp;quot;has_new=true&amp;quot; &amp;gt;&amp;gt; &amp;quot;$GITHUB_OUTPUT&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;          fi&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;      -&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt; name&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; Post to Bluesky&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;        if&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; steps.detect.outputs.has_new == &amp;#39;true&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;        env&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;          BLUESKY_IDENTIFIER&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; ${{ secrets.BLUESKY_IDENTIFIER }}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;          BLUESKY_APP_PASSWORD&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; ${{ secrets.BLUESKY_APP_PASSWORD }}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;          NEW_ARTICLES&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; ${{ steps.detect.outputs.articles }}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;        run&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; |&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;          echo &amp;quot;$NEW_ARTICLES&amp;quot; | while IFS= read -r article; do&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;            [ -z &amp;quot;$article&amp;quot; ] &amp;amp;&amp;amp; continue&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;            bash scripts&#x2F;bluesky-post.sh &amp;quot;$article&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;          done&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;!-- textlint-enable --&gt;
&lt;p&gt;&lt;code&gt;fetch-depth: 2&lt;&#x2F;code&gt; で直前のコミットとの差分を取得できるようにしています。&lt;code&gt;paths: [&#x27;content&#x2F;**&#x27;]&lt;&#x2F;code&gt; でcontent配下に変更がないpush（設定ファイルの変更など）ではワークフロー自体が起動しません。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;投稿スクリプト&quot;&gt;投稿スクリプト&lt;&#x2F;h2&gt;
&lt;p&gt;投稿スクリプトは &lt;code&gt;curl&lt;&#x2F;code&gt; と &lt;code&gt;jq&lt;&#x2F;code&gt; だけで動作します。外部ライブラリは不要です。&lt;&#x2F;p&gt;
&lt;p&gt;処理は大きく5段階に分かれています。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;frontmatterの抽出。&lt;&#x2F;strong&gt; &lt;code&gt;sed&lt;&#x2F;code&gt; でTOMLのfrontmatter領域（&lt;code&gt;+++&lt;&#x2F;code&gt; で囲まれた部分）を取り出し、title、description、tags、&lt;code&gt;social_media_card&lt;&#x2F;code&gt;（OGP画像パス）を個別にパースします。descriptionはTOMLの複数行文字列（&lt;code&gt;&quot;&quot;&quot;&lt;&#x2F;code&gt;）にも対応しています。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;投稿テキストの生成。&lt;&#x2F;strong&gt; フォーマットは以下の通りです。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;📝 Just published:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;#blog #tag1 #tag2&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;descriptionはリンクカードに表示されるため、テキスト本文には含めません。&lt;code&gt;#blog&lt;&#x2F;code&gt; は固定で付与し、記事のタグから最大5個のハッシュタグを追加します。スペースを含むタグ（&quot;Generative AI&quot; など）はBlueskyのハッシュタグとして機能しないためスキップします。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Facetの生成。&lt;&#x2F;strong&gt; Blueskyでハッシュタグをクリック可能にするには、テキスト中の &lt;code&gt;#tag&lt;&#x2F;code&gt; の位置をUTF-8バイトオフセットで指定する &lt;code&gt;facet&lt;&#x2F;code&gt; が必要です。&lt;code&gt;wc -c&lt;&#x2F;code&gt; でバイト位置を算出し、&lt;code&gt;app.bsky.richtext.facet#tag&lt;&#x2F;code&gt; を設定しています。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;OGP画像のアップロード。&lt;&#x2F;strong&gt; frontmatterの &lt;code&gt;social_media_card&lt;&#x2F;code&gt; で指定されたOGP画像を &lt;code&gt;com.atproto.repo.uploadBlob&lt;&#x2F;code&gt; でBlueskyにアップロードし、blobリファレンスを取得します。アップロードに失敗した場合はサムネイルなしで投稿を続行します。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;APIの呼び出し。&lt;&#x2F;strong&gt; &lt;code&gt;com.atproto.server.createSession&lt;&#x2F;code&gt; でセッションを作成し、&lt;code&gt;com.atproto.repo.createRecord&lt;&#x2F;code&gt; でポストを作成します。リンクカードは &lt;code&gt;app.bsky.embed.external&lt;&#x2F;code&gt; で埋め込み、アップロード済みのOGP画像を &lt;code&gt;thumb&lt;&#x2F;code&gt; フィールドに設定します。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;リンクカードについて&quot;&gt;リンクカードについて&lt;&#x2F;h2&gt;
&lt;p&gt;Blueskyは投稿時にURLからOGPを自動取得しません。リンクカードを表示するには、投稿APIで &lt;code&gt;app.bsky.embed.external&lt;&#x2F;code&gt; を明示的に指定する必要があります。サムネイル画像を表示するには、事前に &lt;code&gt;com.atproto.repo.uploadBlob&lt;&#x2F;code&gt; で画像をアップロードし、返却されたblobリファレンスを &lt;code&gt;thumb&lt;&#x2F;code&gt; フィールドに設定します。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;json&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;embed&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;: &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;  &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;$type&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;app.bsky.embed.external&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;  &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;external&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;: {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;uri&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;https:&#x2F;&#x2F;codedchords.dev&#x2F;blog&#x2F;2026&#x2F;03&#x2F;bluesky-auto-post&#x2F;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;title&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;記事タイトル&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;description&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;記事の説明文&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;thumb&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;: { &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;$type&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;blob&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; ...&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;  }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;このスクリプトでは、frontmatterの &lt;code&gt;social_media_card&lt;&#x2F;code&gt; で指定されたOGP画像（WebP&#x2F;PNG&#x2F;JPEG対応）をアップロードしています。画像のアップロードに失敗した場合でも、サムネイルなしのリンクカードとして投稿が作成されるようにフォールバック処理を入れています。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;GitHub_Secretsの設定&quot;&gt;GitHub Secretsの設定&lt;&#x2F;h2&gt;
&lt;p&gt;ワークフローで使用するシークレットは2つです。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;BLUESKY_IDENTIFIER&lt;&#x2F;code&gt; — Blueskyのハンドル&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;BLUESKY_APP_PASSWORD&lt;&#x2F;code&gt; — Blueskyのアプリパスワード（設定画面から生成）&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;アプリパスワードはアカウントのパスワードとは別物で、権限を限定して発行できます。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;まとめ&quot;&gt;まとめ&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;code&gt;git push&lt;&#x2F;code&gt; から自動的にBlueskyへ投稿される仕組みを、GitHub Actionsとシェルスクリプトで構築しました。OGP画像のサムネイル付きリンクカードまで含めて、外部ライブラリに依存せず &lt;code&gt;curl&lt;&#x2F;code&gt; と &lt;code&gt;jq&lt;&#x2F;code&gt; だけで完結しています。この記事自体が最初の自動投稿テストです。&lt;&#x2F;p&gt;
&lt;!-- textlint-disable --&gt;
&lt;h2 id=&quot;References&quot;&gt;References&lt;&#x2F;h2&gt;
&lt;div class=&quot;references&quot;&gt;
    &lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;docs.bsky.app&#x2F;docs&#x2F;advanced-guides&#x2F;posts&quot;&gt;Bluesky&lt;&#x2F;a&gt;. &quot;Sending Post with the Bluesky API&quot;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;atproto.com&#x2F;specs&#x2F;xrpc&quot;&gt;AT Protocol&lt;&#x2F;a&gt;. &quot;XRPC Specification&quot;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;

&lt;&#x2F;div&gt;
&lt;!-- textlint-enable --&gt;
</content>
        <summary type="html">ブログの新規記事をmainにpushするだけで、Blueskyに自動投稿される仕組みをGitHub ActionsとAT Protocol APIで構築しました。git diffによる新規記事の判定、リンクカード付き投稿、ハッシュタグのfacet生成まで、シェルスクリプト一本で実現しています。</summary>
        </entry><entry xml:lang="en">
        <title>Mac環境のリフレッシュ</title>
        <published>2026-03-17T15:34:11+09:00</published>
        <updated>2026-03-17T15:34:11+09:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2026/03/mac-environment-refresh/" type="text/html"/>
        <id>https://codedchords.dev/blog/2026/03/mac-environment-refresh/</id>
        
            <content type="html">&lt;!-- textlint-disable --&gt;
&lt;img
  src=&quot;https:&amp;#x2F;&amp;#x2F;codedchords.dev&amp;#x2F;blog&amp;#x2F;2026&amp;#x2F;03&amp;#x2F;mac-environment-refresh&amp;#x2F;cover.webp?h=9246e8ce05db44c2688d&quot;
  alt=&quot;Cover&quot; width=&quot;1792&quot; height=&quot;1024&quot; loading=&quot;lazy&quot;
&#x2F;&gt;&lt;!-- textlint-enable --&gt;
&lt;details&gt;
&lt;summary&gt;Table of Contents&lt;&#x2F;summary&gt;
&lt;!-- toc --&gt;
&lt;&#x2F;details&gt;
&lt;p&gt;見送っていたMac環境のリフレッシュを実施しました。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;MacPaw関連ソフトウェアの見直し&quot;&gt;MacPaw関連ソフトウェアの見直し&lt;&#x2F;h2&gt;
&lt;p&gt;MacPaw&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-1-1&quot;&gt;&lt;a href=&quot;#fn-1&quot;&gt;1&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;の次の2つのソフトウェアを使用していました。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;CleanMyMac X&lt;&#x2F;strong&gt;: macOSのメンテナンス・ユーティリティ&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Gemini 2&lt;&#x2F;strong&gt;: 重複ファイル削除ツール&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;いずれもサブスクリプションが中心ですが、私は2022年にロシアのウクライナ侵攻が起こった際に支援のつもりでLifeTimeの買い切りで購入しています。コストも発生せず、どちらも便利なツールです。&lt;&#x2F;p&gt;
&lt;p&gt;しかし、常駐して僅かですがリソースを食っているのが気になっていました。
今回はどちらもアンインストールして、CLI代替ツールに移行しました。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;Mole_—_macOSクリーンアップツール&quot;&gt;Mole — macOSクリーンアップツール&lt;&#x2F;h2&gt;
&lt;!-- textlint-disable --&gt;
&lt;iframe class=&quot;hatenablogcard&quot; src=&quot;https:&#x2F;&#x2F;hatenablog-parts.com&#x2F;embed?url=https:&amp;#x2F;&amp;#x2F;github.com&amp;#x2F;tw93&amp;#x2F;mole&quot; width=&quot;100%&quot; height=&quot;155&quot; frameborder=&quot;0&quot; scrolling=&quot;no&quot; loading=&quot;lazy&quot;&gt;&lt;&#x2F;iframe&gt;
&lt;!-- textlint-enable --&gt;
&lt;p&gt;macOSのクリーンナップと最適化に特化したコマンドラインツールです。
CleanMyMac、AppCleaner、DaisyDisk、iStat Menusなどの機能を1コマンドでカバーしていると謳っています。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;mo&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; clean&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;      # キャッシュ・ログ・ブラウザ残骸の削除&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;mo&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; uninstall&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;  # アプリの完全アンインストール&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;mo&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; optimize&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;   # キャッシュ再構築・サービスリフレッシュ&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;mo&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; analyze&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;    # ディスク使用量の可視化&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;mo&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; status&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;     # CPU&#x2F;GPU&#x2F;メモリ&#x2F;ディスク&#x2F;ネットワークのリアルタイム監視&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;mo&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; purge&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;      # 開発プロジェクトのビルド成果物削除&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;mo&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; installer&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;  # Downloads内の.dmg&#x2F;.pkgの整理&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;結構危険な処理をするツールですが、いずれも&lt;code&gt;--dry-run&lt;&#x2F;code&gt;オプションがサポートされており、実際に削除する前に検証できます。&lt;&#x2F;p&gt;
&lt;p&gt;実際、CleanMyMac Xで使用していた機能のうちマルウェアスキャン以外はほぼカバーされています。
マルウェアスキャンについては、macOS標準のXProtectとGatekeeperがかなり優秀なので、基本的に追加のスキャナは不要と判断しました。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;Czkawka（チカフカ）_—_不要ファイル検出ツール&quot;&gt;Czkawka（チカフカ） — 不要ファイル検出ツール&lt;&#x2F;h2&gt;
&lt;!-- textlint-disable --&gt;
&lt;iframe class=&quot;hatenablogcard&quot; src=&quot;https:&#x2F;&#x2F;hatenablog-parts.com&#x2F;embed?url=https:&amp;#x2F;&amp;#x2F;github.com&amp;#x2F;qarmin&amp;#x2F;czkawka&quot; width=&quot;100%&quot; height=&quot;155&quot; frameborder=&quot;0&quot; scrolling=&quot;no&quot; loading=&quot;lazy&quot;&gt;&lt;&#x2F;iframe&gt;
&lt;!-- textlint-enable --&gt;
&lt;p&gt;主に重複ファイルの削除に使用していたGemini 2の代替です。名前はポーランド語で「しゃっくり」を意味します。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;sahib&#x2F;rmlint&quot;&gt;rmlint&lt;&#x2F;a&gt;も検討しましたが、rmlintはバイト単位での重複判定のみで、Gemini 2のように画像の類似性による重複判定には対応していません。&lt;&#x2F;p&gt;
&lt;p&gt;その点Czkawkaは、パーセプチュアルハッシュによる類似画像検出をサポートしています。GUI版もありますが、安定のCLI版を使っています。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# 重複ファイル検出: -d 検索先 -e 除外先 -m 最小25B -s hash比較 -D aeo(最古以外を削除)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;czkawka_cli&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; dup -d ~&#x2F;Documents -e ~&#x2F;Documents&#x2F;Archive -m&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 25&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; -x 7z rar IMAGE -s hash -f results.txt -D aeo&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# 空フォルダ検出: 複数ディレクトリ指定可&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;czkawka_cli&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; empty-folders -d ~&#x2F;Documents ~&#x2F;Downloads -f results.txt&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# 巨大ファイル検出: -n 上位25件 -x VIDEO拡張子を除外&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;czkawka_cli&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; big -d ~&#x2F;Documents -e ~&#x2F;Documents&#x2F;Archive -n&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 25&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; -x VIDEO -f results.txt&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# 類似画像検出: パーセプチュアルハッシュで視覚的に似た画像を検出&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;czkawka_cli&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; image -d ~&#x2F;Pictures -e ~&#x2F;Pictures&#x2F;Wallpapers -f results.txt&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# 壊れたシンボリックリンク検出&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;czkawka_cli&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; symlinks -d ~&#x2F;Projects -e ~&#x2F;Projects&#x2F;.git -x jpg -f results.txt&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# 破損ファイル検出: ヘッダが壊れたファイル等を検出&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;czkawka_cli&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; broken -d ~&#x2F;Downloads -f results.txt&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;重複ファイル、類似画像、空ファイル・フォルダ、一時ファイル、破損ファイル、拡張子不一致、不正ファイル名など、Gemini 2以上に多彩な検出機能を備えています。&lt;&#x2F;p&gt;
&lt;p&gt;なお、SenseiとCocktailは引き続き使用しています。Senseiはハードウェア情報やSSDのTrim管理に、CocktailはmacOSの定期メンテナンスタスクの自動実行に、それぞれ役割が明確なので残しました。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;メニューバーの整理&quot;&gt;メニューバーの整理&lt;&#x2F;h2&gt;
&lt;p&gt;MacBookでメニューバーにたくさんアイコンが並ぶと、ノッチの裏に隠れて見えなくなる問題があります。この対策としてメニュー表示管理ツールを使用していました。&lt;&#x2F;p&gt;
&lt;p&gt;Bartenderから数年前に&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;jordanbaird&#x2F;Ice&quot;&gt;Ice&lt;&#x2F;a&gt;へ移行しましたが、macOS Tahoeではメニュー構造が変わった影響で動作が不安定になっていました。&lt;&#x2F;p&gt;
&lt;p&gt;代替として次のようなツールがありますが、いずれも新しいmacOSのメニュー構造の変更に対応しきれていないようでした。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Hidden Bar&lt;&#x2F;li&gt;
&lt;li&gt;Bartender 5（有料）&lt;&#x2F;li&gt;
&lt;li&gt;Vanilla&lt;&#x2F;li&gt;
&lt;li&gt;iBar&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;しかし、macOS Tahoeではメニューバーのカスタマイズ機能が大幅に強化されました。「システム設定 &amp;gt; メニューバー &amp;gt; メニューバーの操作」から、次の操作が可能になっています。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;アプリごとにメニューバーへの表示のオン・オフを制御&lt;&#x2F;li&gt;
&lt;li&gt;Apple純正機能はコントロールセンターへ移動可能&lt;&#x2F;li&gt;
&lt;li&gt;Command+ドラッグでアイコンの並び替え&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;サードパーティ製ツールのように表示の動的な切り替えやレイアウト変更には対応していませんが、常駐アイコンの大半を整理できました。もうサードパーティ製ツールは不要です。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;ブラウザArcの代替&quot;&gt;ブラウザArcの代替&lt;&#x2F;h2&gt;
&lt;p&gt;数年前に彗星のごとく登場したArcを愛用していましたが、2025年5月にThe Browser Companyが開発終了を発表しました。理由は「ほとんどの人にとってArcは違いが大きすぎて学習コストに見合わなかった」という&quot;novelty tax&quot;問題とのことです。後継としてAIブラウザ「Dia」の開発に注力するとされていますが、Arc自体はセキュリティ修正のみのメンテナンスモードに入っています。&lt;&#x2F;p&gt;
&lt;p&gt;当初はGoogle Chrome + Side Space拡張機能でほぼArcと同等のことができるかと試していました。しかし、Arcの全機能を再現しようとすると拡張の組み合わせが増えるばかりで、本末転倒だと気づきました。&lt;&#x2F;p&gt;
&lt;p&gt;結局、Safariに落ち着いています。iCloudとの連携、省電力性能、macOS標準のパスキー対応など、Apple製品で統一している環境であれば素直にSafariが最適という結論です。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;まとめ&quot;&gt;まとめ&lt;&#x2F;h2&gt;
&lt;p&gt;GUIの常駐アプリをCLIに置き換え、メニューバーをOS標準機能で整理し、ブラウザもSafariに一本化しました。&lt;&#x2F;p&gt;
&lt;p&gt;やっとメニューバーが整理でき、&lt;code&gt;mo clean&lt;&#x2F;code&gt;一発でMacのクリーンナップもできる。そういう小さな快適さの積み重ねで、深呼吸できた心地がします。ゴミの山は鼻をつまんで走り抜けるに限ります。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;References&quot;&gt;References&lt;&#x2F;h2&gt;
&lt;!-- textlint-disable --&gt;
&lt;div class=&quot;references&quot;&gt;
    &lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;tw93&#x2F;mole&quot;&gt;GitHub - tw93&#x2F;mole&lt;&#x2F;a&gt;. &quot;Mole - Deep clean and optimize your Mac&quot;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;qarmin&#x2F;czkawka&quot;&gt;GitHub - qarmin&#x2F;czkawka&lt;&#x2F;a&gt;. &quot;Multi functional app to find duplicates, empty folders, similar images etc.&quot;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;cindori.com&#x2F;sensei&quot;&gt;Sensei — Cindori&lt;&#x2F;a&gt;. 「Mac Performance Monitor &amp;amp; Cleaner」&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.maintain.se&#x2F;cocktail&#x2F;&quot;&gt;Cocktail — Maintain&lt;&#x2F;a&gt;. 「A perfect mixture for macOS」&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;support.apple.com&#x2F;guide&#x2F;mac-help&#x2F;change-menu-bar-settings-mchlad96d366&#x2F;mac&quot;&gt;Apple Support&lt;&#x2F;a&gt;. &quot;Change Menu Bar settings on Mac&quot;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.engadget.com&#x2F;ai&#x2F;the-browser-company-stops-active-development-of-arc-in-favor-of-new-ai-focused-product-153045276.html&quot;&gt;Engadget&lt;&#x2F;a&gt;. &quot;The Browser Company stops active development of Arc in favor of new AI-focused product&quot;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;

&lt;&#x2F;div&gt;
&lt;!-- textlint-enable --&gt;
&lt;section class=&quot;footnotes&quot;&gt;
&lt;ol class=&quot;footnotes-list&quot;&gt;
&lt;li id=&quot;fn-1&quot;&gt;
&lt;p&gt;Macのユーティリティ系ソフトウェアを開発・販売しているウクライナのベンダー &lt;a href=&quot;#fr-1-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;&#x2F;section&gt;
</content>
        <summary type="html">無為がループした一年で放置していたMac環境をリフレッシュしました。MacPawのGUIツールをCLIへ移行し、メニューバーをmacOS Tahoe標準機能で整理し、ArcからSafariへ乗り換えた記録です。</summary>
        </entry><entry xml:lang="en">
        <title>CLAUDE.mdを太らせない — リポジトリ設計で実現するClaude Codeのガードレールと再現性</title>
        <published>2026-03-08T07:04:00+09:00</published>
        <updated>2026-03-08T07:04:00+09:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2026/03/claude-code-repo-architecture/" type="text/html"/>
        <id>https://codedchords.dev/blog/2026/03/claude-code-repo-architecture/</id>
        
            <content type="html">&lt;!-- textlint-disable --&gt;
&lt;img
  src=&quot;https:&amp;#x2F;&amp;#x2F;codedchords.dev&amp;#x2F;blog&amp;#x2F;2026&amp;#x2F;03&amp;#x2F;claude-code-repo-architecture&amp;#x2F;cover.webp?h=4d465f543f1815d72ad1&quot;
  alt=&quot;Cover&quot; width=&quot;1792&quot; height=&quot;1024&quot; loading=&quot;lazy&quot;
&#x2F;&gt;&lt;!-- textlint-enable --&gt;
&lt;details&gt;
&lt;summary&gt;Table of Contents&lt;&#x2F;summary&gt;
&lt;!-- toc --&gt;
&lt;&#x2F;details&gt;
&lt;span id=&quot;continue-reading&quot;&gt;&lt;&#x2F;span&gt;&lt;h2 id=&quot;CLAUDE.mdが肥大化していませんか&quot;&gt;CLAUDE.mdが肥大化していませんか&lt;&#x2F;h2&gt;
&lt;p&gt;Claude Codeを使い込むほど、CLAUDE.mdは育っていきます。ショートコードの構文リファレンス、コミットの手順、画像生成のコマンド、レビューのチェックリスト。気がつけば400行を超え、重要なルールが大量の参考情報に埋もれている――そんな状態になっていないでしょうか。&lt;&#x2F;p&gt;
&lt;p&gt;CLAUDE.mdはセッション開始時に毎回読み込まれるコンテキストです。ここに情報を詰め込みすぎると、本当に守ってほしいルールの優先度が下がります。かといって削りすぎれば、Claudeは暗黙知を推測で補おうとして事故を起こします。&lt;&#x2F;p&gt;
&lt;p&gt;このブログ（Zola静的サイト）の運用で、CLAUDE.mdを458行から117行へ削減しながら、むしろルール遵守の精度と作業の再現性を向上させた設計パターンを紹介します。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;4層アーキテクチャという考え方&quot;&gt;4層アーキテクチャという考え方&lt;&#x2F;h2&gt;
&lt;p&gt;この整理は、Shraddha Bharuka氏が提唱する「The Anatomy of a Claude Code Project」の考え方をベースにしています。&lt;&#x2F;p&gt;
&lt;!-- textlint-disable --&gt;
&lt;blockquote class=&quot;twitter-tweet&quot;&gt;&lt;p lang=&quot;en&quot; dir=&quot;ltr&quot;&gt;Most people treat CLAUDE.md like a prompt file.&lt;br&gt;&lt;br&gt;That&#x27;s the mistake.&lt;br&gt;&lt;br&gt;If you want Claude Code to feel like a senior engineer living inside your repo, your project needs structure.&lt;br&gt;&lt;br&gt;Claude needs 4 things at all times:&lt;br&gt;&lt;br&gt;• the why → what the system does&lt;br&gt;• the map → where things… &lt;a href=&quot;https:&#x2F;&#x2F;t.co&#x2F;wumSCnNxHF&quot;&gt;pic.twitter.com&#x2F;wumSCnNxHF&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;&amp;mdash; Shraddha Bharuka (@BharukaShraddha) &lt;a href=&quot;https:&#x2F;&#x2F;twitter.com&#x2F;BharukaShraddha&#x2F;status&#x2F;2029836408232497678?ref_src=twsrc%5Etfw&quot;&gt;March 6, 2026&lt;&#x2F;a&gt;&lt;&#x2F;blockquote&gt; &lt;script async src=&quot;https:&#x2F;&#x2F;platform.twitter.com&#x2F;widgets.js&quot; charset=&quot;utf-8&quot;&gt;&lt;&#x2F;script&gt;
&lt;!-- textlint-enable --&gt;
&lt;p&gt;氏の整理ではRepo Memory &#x2F; Reusable Expert Modes &#x2F; Guardrails &#x2F; Progressive Contextという4層が示されています。本記事ではClaude CodeのAuto Memory機能との混同を避けるため、一部の用語を変更しています。&lt;&#x2F;p&gt;
&lt;p&gt;リポジトリに散らばるClaude Code関連のファイルを、責務で4つの層に分離します。&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;層&lt;&#x2F;th&gt;&lt;th&gt;場所&lt;&#x2F;th&gt;&lt;th&gt;役割&lt;&#x2F;th&gt;&lt;th&gt;読み込みタイミング&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;Project Instructions&lt;&#x2F;td&gt;&lt;td&gt;&lt;code&gt;.&#x2F;CLAUDE.md&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;WHY・WHAT・HOW の要約&lt;&#x2F;td&gt;&lt;td&gt;毎セッション（常時）&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Workflows&lt;&#x2F;td&gt;&lt;td&gt;&lt;code&gt;.&#x2F;.claude&#x2F;commands&#x2F;&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;再利用可能なワークフロー&lt;&#x2F;td&gt;&lt;td&gt;コマンド呼び出し時&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Guardrails&lt;&#x2F;td&gt;&lt;td&gt;&lt;code&gt;.&#x2F;.claude&#x2F;settings.json&lt;&#x2F;code&gt; (Hooks)&lt;&#x2F;td&gt;&lt;td&gt;機械的な禁止ルール&lt;&#x2F;td&gt;&lt;td&gt;ツール実行の前後&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Progressive Context&lt;&#x2F;td&gt;&lt;td&gt;&lt;code&gt;.&#x2F;docs&#x2F;&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;詳細リファレンス&lt;&#x2F;td&gt;&lt;td&gt;必要に応じて&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;それぞれの層には明確な設計原則があります。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;CLAUDE.md_—_Project_Instructions&quot;&gt;CLAUDE.md — Project Instructions&lt;&#x2F;h2&gt;
&lt;p&gt;Claude Codeにはもうひとつ、Auto Memoryという記憶の仕組みがあります。これはClaude自身がセッション中に学んだこと――ビルドコマンドの癖、デバッグで得た知見、ユーザーの好み――を &lt;code&gt;~&#x2F;.claude&#x2F;projects&#x2F;&amp;lt;project&amp;gt;&#x2F;memory&#x2F;&lt;&#x2F;code&gt; に自動で書き残す機能です。CLAUDE.mdが「ユーザーからClaudeへの指示」であるのに対し、Auto Memoryは「Claudeが自分で蓄積する学習ノート」です。両者はセッション開始時に読み込まれますが、役割が異なります。この記事で扱う4層アーキテクチャは、ユーザーが意図的に設計する情報配置のパターンです。Auto Memoryはその外側で自動的に機能する補完的な仕組みとして捉えてください。&lt;&#x2F;p&gt;
&lt;p&gt;CLAUDE.mdには3つの情報だけを書きます。&lt;&#x2F;p&gt;
&lt;dl&gt;
&lt;dt&gt;目的（WHY）&lt;&#x2F;dt&gt;
&lt;dd&gt;このリポジトリが何であるか。Zolaブログであること、tabi テーマを使っていること。新しいセッションのClaudeがプロジェクトを理解するための最小限の情報です。&lt;&#x2F;dd&gt;
&lt;dt&gt;マップ（WHAT）&lt;&#x2F;dt&gt;
&lt;dd&gt;記事のfrontmatterフォーマット、タグの命名規則への参照、ショートコードドキュメントへの参照。詳細はdocsに委ね、CLAUDE.mdには「どこを見ればよいか」だけを書きます。&lt;&#x2F;dd&gt;
&lt;dt&gt;ルール（HOW）&lt;&#x2F;dt&gt;
&lt;dd&gt;文体はですます調、descriptionは句点で終える、textlint-disableの使い方。Claudeが記事を書くときに常に意識すべき制約です。&lt;&#x2F;dd&gt;
&lt;&#x2F;dl&gt;
&lt;p&gt;実際のCLAUDE.mdから、ショートコードのセクションを例に挙げます。以前は13個のショートコードそれぞれに構文、パラメータ一覧、使用例を書いていました。250行です。整理後は「ショートコードはtextlint-disableで囲む」というルールと、詳細ドキュメントへの参照だけになりました。個別の構文はClaude自身が必要なときに &lt;code&gt;docs&#x2F;&lt;&#x2F;code&gt; 配下のショートコード定義書を読みに行けばよいのです。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;Commands_—_Workflows&quot;&gt;Commands — Workflows&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;code&gt;.claude&#x2F;commands&#x2F;&lt;&#x2F;code&gt; に配置したMarkdownファイルは、&lt;code&gt;&#x2F;コマンド名&lt;&#x2F;code&gt; で呼び出せるワークフロー定義です。セッションをまたいでも同じ手順が実行されるため、作業品質の一貫性が生まれます。&lt;&#x2F;p&gt;
&lt;p&gt;このブログでは6つのコマンドを定義しています。&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;コマンド&lt;&#x2F;th&gt;&lt;th&gt;用途&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;&#x2F;article-review&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;記事の品質レビュー（frontmatter、文体、アセット確認）&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;&#x2F;article-publish&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;記事の公開（レビュー → OGP再生成 → ビルド検証 → コミット → push）&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;&#x2F;article-cover&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;カバー画像生成（記事内容からDALL-E 3でcover.webpを生成）&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;&#x2F;blog-review&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;ブログ設定のコードレビュー&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;&#x2F;blog-refactor&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;設定リファクタリングの手順ガイド&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;&#x2F;blog-release&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;ブランチ運用のリリースフロー（CHANGELOG → PR → マージ → タグ）&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;記事系（article-）とブログ基盤系（blog-）で命名体系を分けています。これは運用フローが根本的に異なるためです。記事はmainに直接push、ブログ設定はブランチを切ってPR経由でマージします。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;code&gt;&#x2F;article-publish&lt;&#x2F;code&gt; の定義から、要点を抜粋して見てみましょう。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;markdown&quot; data-name=&quot;.claude&#x2F;commands&#x2F;article-publish.md&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;---&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;description&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; Publish an article. Run review, regenerate OGP,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;  verify build, commit, and push to main automatically.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;---&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-heading z-markdown z-heading z-\31  z-markdown&quot;&gt;# Article Publish&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;Execute the full publish workflow automatically.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;Prerequisite: the user has already confirmed the article&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;via &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-raw z-markdown z-markup z-inline z-raw z-string z-markdown&quot;&gt;`zola serve`&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt; preview.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-heading z-markdown z-heading z-\32  z-markdown&quot;&gt;## Steps&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;Execute in order. Stop and report if any step fails.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-heading z-markdown z-heading z-\33  z-markdown&quot;&gt;### 1. Run &#x2F;article-review&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;Execute the full article quality review.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;If issues are found, stop and fix them before continuing.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-heading z-markdown z-heading z-\33  z-markdown&quot;&gt;### 2. Regenerate OGP Image&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-list z-begin z-markdown&quot;&gt;-&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt; Delete the existing OGP image&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-list z-begin z-markdown&quot;&gt;-&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt; Run &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-raw z-markdown z-markup z-inline z-raw z-string z-markdown&quot;&gt;`npm run ogp`&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt; to regenerate&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-heading z-markdown z-heading z-\33  z-markdown&quot;&gt;### 3. zola check&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;Run &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-raw z-markdown z-markup z-inline z-raw z-string z-markdown&quot;&gt;`zola check`&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt; to verify no broken links or build errors.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-heading z-markdown z-heading z-\33  z-markdown&quot;&gt;### 4. Stage &amp;amp; Commit&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-list z-begin z-markdown&quot;&gt;-&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-raw z-markdown z-markup z-inline z-raw z-string z-markdown&quot;&gt; `git add .`&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt; to stage all changes&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-list z-begin z-markdown&quot;&gt;-&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt; Use &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-raw z-markdown z-markup z-inline z-raw z-string z-markdown&quot;&gt;`&#x2F;simple-commit:commit`&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt; skill to create the commit&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-heading z-markdown z-heading z-\33  z-markdown&quot;&gt;### 5. Push&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;Run &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-raw z-markdown z-markup z-inline z-raw z-string z-markdown&quot;&gt;`git push origin main`&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt; to publish.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;このコマンドが実行する手順は、以前はCLAUDE.mdに散在するルールの組み合わせで「わかっているはず」と暗黙に期待していたものです。コマンドとして明示することで、どのセッションでも同じ品質で公開作業が完了します。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;Hooks_—_Guardrails&quot;&gt;Hooks — Guardrails&lt;&#x2F;h2&gt;
&lt;p&gt;Hooksは &lt;code&gt;.claude&#x2F;settings.json&lt;&#x2F;code&gt; に定義する、ツール実行の前後に自動で走るチェックです。CLAUDE.mdに「〜するな」と書いても、Claudeは忘れることがあります。Hooksは忘れません。&lt;&#x2F;p&gt;
&lt;p&gt;このブログで設定しているガードレールです。&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;タイミング&lt;&#x2F;th&gt;&lt;th&gt;対象&lt;&#x2F;th&gt;&lt;th&gt;動作&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;PreToolUse&lt;&#x2F;td&gt;&lt;td&gt;&lt;code&gt;git commit&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;ブロック。&lt;code&gt;&#x2F;simple-commit:commit&lt;&#x2F;code&gt; の使用を強制&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;PreToolUse&lt;&#x2F;td&gt;&lt;td&gt;&lt;code&gt;git add &amp;lt;個別ファイル&amp;gt;&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;ブロック。&lt;code&gt;git add .&lt;&#x2F;code&gt; のみ許可&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;PreToolUse&lt;&#x2F;td&gt;&lt;td&gt;&lt;code&gt;themes&#x2F;&lt;&#x2F;code&gt; への Write&#x2F;Edit&lt;&#x2F;td&gt;&lt;td&gt;ブロック。サブモジュール保護&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;PostToolUse&lt;&#x2F;td&gt;&lt;td&gt;content&#x2F;*.md への Write&#x2F;Edit&lt;&#x2F;td&gt;&lt;td&gt;Markdown画像記法 &lt;code&gt;![]()&lt;&#x2F;code&gt; を検出し、imageショートコード使用を指示&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;&lt;code&gt;git commit&lt;&#x2F;code&gt; のブロックを例に、実装を見てみましょう。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;json&quot; data-name=&quot;.claude&#x2F;settings.json（抜粋）&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;  &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;hooks&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;: {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;PreToolUse&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;: [&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;      {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;        &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;matcher&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;Bash&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;        &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;hooks&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;: [&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;          {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;            &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;type&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;command&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;            &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;command&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;jq -r &amp;#39;.tool_input.command&amp;#39; | grep -qE &amp;#39;^git commit&amp;#39; &amp;amp;&amp;amp; echo &amp;#39;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt;\&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;decision&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt;\&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt;\&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;block&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt;\&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt;\&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;reason&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt;\&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt;\&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;git commit 直接実行は禁止です。&#x2F;simple-commit:commit スキルを使ってください&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt;\&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt;}&amp;#39; || true&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;          }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;        ]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;      }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    ]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;  }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Hooksの設計方針は「禁止ルールはHooksに、正のガイダンスはCLAUDE.mdに」です。「〜するな」はHooksで機械的にブロックし、「〜の代わりにこうする」はCLAUDE.mdやCommandsで伝えます。&lt;&#x2F;p&gt;
&lt;p&gt;この分離によってCLAUDE.mdから禁止文を削除できました。前向きなガイダンスだけが残り、読みやすいドキュメントになっています。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;docs&#x2F;_—_Progressive_Context&quot;&gt;docs&#x2F; — Progressive Context&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;code&gt;docs&#x2F;&lt;&#x2F;code&gt; にはCLAUDE.mdに収まらない詳細情報を配置します。Claudeは必要に応じてこれらのファイルを読みに行きます。&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;ファイル&lt;&#x2F;th&gt;&lt;th&gt;内容&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;docs&#x2F;tabi-shortcodes.md&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;ショートコード構文リファレンス&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;docs&#x2F;tag-rule.md&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;タグ命名規則&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;docs&#x2F;TODO.md&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;作業計画・意思決定の記録&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;docs&#x2F;architectural-decision.md&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;アーキテクチャ判断の記録&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;この層の設計原則は「CLAUDE.mdに場所を教え、詳細はdocsに置く」です。CLAUDE.mdのショートコードセクションには &lt;code&gt;See docs&#x2F;tabi-shortcodes.md&lt;&#x2F;code&gt; と一行書くだけで、Claudeはショートコードを使うときにそのファイルを読みに行きます。&lt;&#x2F;p&gt;
&lt;p&gt;毎セッションで250行のショートコードリファレンスをコンテキストに読み込む必要はありません。必要なときに必要な分だけ読む。これがProgressive Contextの考え方です。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;責務分離の判断基準&quot;&gt;責務分離の判断基準&lt;&#x2F;h2&gt;
&lt;p&gt;新しいルールや手順を追加するとき、どの層に置くかの判断基準をまとめます。&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;条件&lt;&#x2F;th&gt;&lt;th&gt;配置先&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;毎セッションで必ず意識すべきルール&lt;&#x2F;td&gt;&lt;td&gt;CLAUDE.md&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;複数ステップのワークフロー&lt;&#x2F;td&gt;&lt;td&gt;Commands&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;「〜するな」という禁止ルール&lt;&#x2F;td&gt;&lt;td&gt;Hooks&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;必要なときだけ参照する詳細情報&lt;&#x2F;td&gt;&lt;td&gt;docs&#x2F;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;迷ったときは「これをCLAUDE.mdから消したら、Claudeは間違えるか？」と自問してみてください。答えがNoなら、それはCLAUDE.mdに置くべき情報ではありません。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;まとめ&quot;&gt;まとめ&lt;&#x2F;h2&gt;
&lt;p&gt;CLAUDE.mdへ全部書く運用から、4層に分離する運用へ変えた結果を振り返ります。&lt;&#x2F;p&gt;
&lt;p&gt;CLAUDE.mdは458行から117行になりました。削減した341行が消えたのではなく、適切な層へ移動しただけです。ショートコードのリファレンスは&lt;code&gt;docs&#x2F;&lt;&#x2F;code&gt;へ、公開フローはCommandsへ、禁止ルールはHooksへ。それぞれの情報が、もっとも効果的に機能する場所へ収まりました。&lt;&#x2F;p&gt;
&lt;p&gt;コンテキストが長いほど個々のルールへの注意が分散し、遵守率が下がります。CLAUDE.mdが短ければ、書いたルールが確実に守られます。ワークフローがCommandsに定義されていれば、セッション間で品質がブレません。Hooksが禁止ルールを機械的に強制すれば、「AIが忘れる」問題は起きません。&lt;&#x2F;p&gt;
&lt;p&gt;この4層アーキテクチャは、ブログに限らずあらゆるClaude Codeプロジェクトへ適用できるパターンです。CLAUDE.mdが長くなってきたら、責務の分離を検討してみてください。&lt;&#x2F;p&gt;
&lt;!-- textlint-disable --&gt;
&lt;div class=&quot;references&quot;&gt;
    &lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;x.com&#x2F;BharukaShraddha&#x2F;status&#x2F;2029836408232497678&quot;&gt;Shraddha Bharuka (@BharukaShraddha)&lt;&#x2F;a&gt;. &quot;The Anatomy of a Claude Code Project&quot;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;docs.anthropic.com&#x2F;en&#x2F;docs&#x2F;claude-code&#x2F;overview&quot;&gt;Anthropic&lt;&#x2F;a&gt;. &quot;Claude Code Overview&quot;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;docs.anthropic.com&#x2F;en&#x2F;docs&#x2F;claude-code&#x2F;memory&quot;&gt;Anthropic&lt;&#x2F;a&gt;. &quot;Memory&quot;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;docs.anthropic.com&#x2F;en&#x2F;docs&#x2F;claude-code&#x2F;best-practices&quot;&gt;Anthropic&lt;&#x2F;a&gt;. &quot;Best practices&quot;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;docs.anthropic.com&#x2F;en&#x2F;docs&#x2F;claude-code&#x2F;hooks&quot;&gt;Anthropic&lt;&#x2F;a&gt;. &quot;Hooks&quot;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;docs.anthropic.com&#x2F;en&#x2F;docs&#x2F;claude-code&#x2F;skills&quot;&gt;Anthropic&lt;&#x2F;a&gt;. &quot;Skills&quot;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;

&lt;&#x2F;div&gt;
&lt;!-- textlint-enable --&gt;
</content>
        <summary type="html">CLAUDE.mdに全部書いてしまい、肝心なルールが埋もれていませんか。CLAUDE.md、Commands、Hooks、docsの4層に責務を分離し、AIが忘れないガードレールとセッション間で一貫したワークフローを実現するリポジトリ設計パターンを、実例とともに解説します。</summary>
        </entry><entry xml:lang="en">
        <title>SPFのDNSルックアップ上限10回、あなたの組織は大丈夫？</title>
        <published>2026-03-03T00:00:00+00:00</published>
        <updated>2026-03-03T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2026/03/spf-lookup-limit-risk/" type="text/html"/>
        <id>https://codedchords.dev/blog/2026/03/spf-lookup-limit-risk/</id>
        
            <content type="html">&lt;!-- textlint-disable --&gt;
&lt;p&gt;&lt;img
  src=&quot;https:&amp;#x2F;&amp;#x2F;codedchords.dev&amp;#x2F;blog&amp;#x2F;2026&amp;#x2F;03&amp;#x2F;spf-lookup-limit-risk&amp;#x2F;cover.webp?h=bc1f2cf07dfaabe490a7&quot;
  alt=&quot;Cover&quot; width=&quot;1792&quot; height=&quot;1024&quot; loading=&quot;lazy&quot;
&#x2F;&gt;
&lt;div class=&quot;admonition info&quot;&gt;
    &lt;div class=&quot;admonition-icon admonition-icon-info&quot;&gt;&lt;&#x2F;div&gt;
    &lt;div class=&quot;admonition-content&quot;&gt;
        &lt;strong class=&quot;admonition-title&quot;&gt;転載元&lt;&#x2F;strong&gt;
        &lt;p&gt;この記事は &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;zenn.dev&#x2F;yostos&#x2F;articles&#x2F;spf-lookup-limit-risk&quot;&gt;Zenn&lt;&#x2F;a&gt; に掲載した記事の転載です。&lt;&#x2F;p&gt;

    &lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;&#x2F;p&gt;
&lt;!-- textlint-enable --&gt;
&lt;details&gt;
&lt;summary&gt;Table of Contents&lt;&#x2F;summary&gt;
&lt;!-- toc --&gt;
&lt;&#x2F;details&gt;
&lt;h2 id=&quot;はじめに&quot;&gt;はじめに&lt;&#x2F;h2&gt;
&lt;p&gt;「ある日突然、自組織からのメールが取引先に届かなくなった」——そんな事態が、メール配信サービスを複数利用している組織で実際に起こり得ます。原因は、SPF（Sender Policy Framework）のDNSルックアップ上限です。&lt;&#x2F;p&gt;
&lt;p&gt;外部のメール配信サービスを導入するたびにSPFレコードへ &lt;code&gt;include&lt;&#x2F;code&gt; を追加していくと、気づかないうちに上限へ近づきます。しかも、上限超過のトリガーは自組織の操作ではなく、外部サービス側の設定変更かもしれません。&lt;&#x2F;p&gt;
&lt;p&gt;本記事では、SPFのDNSルックアップ上限の仕組みを解説し、上限超過のリスクと対策を整理します。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;SPFの仕組みとDNSルックアップ上限&quot;&gt;SPFの仕組みとDNSルックアップ上限&lt;&#x2F;h2&gt;
&lt;p&gt;SPFは、メールの送信元ドメインが「どのサーバーからの送信を許可しているか」をDNSのTXTレコードで宣言する仕組みです。受信側メールサーバーは、送信元IPアドレスがSPFレコードに含まれているかを検証し、正当な送信元かどうかを判断します。&lt;&#x2F;p&gt;
&lt;p&gt;SPFレコードの例を示します。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;v=spf1 ip4:192.0.2.0&#x2F;24 include:spf.example.com ~all&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;この例では、&lt;code&gt;192.0.2.0&#x2F;24&lt;&#x2F;code&gt; のIPレンジからの送信と、&lt;code&gt;spf.example.com&lt;&#x2F;code&gt; が許可する送信元を正当とみなします。&lt;&#x2F;p&gt;
&lt;p&gt;SPFの検証は受信側メールサーバーで行われます。メールを受け取ったサーバーが送信元ドメインのSPFレコードをDNSに問い合わせ、送信元IPが許可されているかを確認します。この検証過程でDNSルックアップが発生しますが、RFC 7208（Section 4.6.4）により、1回のSPF検証で実行できるDNSルックアップは最大10回と制限されています。この制限は、SPF検証によるDNSサーバーへの負荷を防ぐために設けられたものです。&lt;&#x2F;p&gt;
&lt;p&gt;すべてのメカニズムがDNSルックアップを消費するわけではありません。消費するメカニズムとしないメカニズムを表にまとめます。&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;メカニズム &#x2F; 修飾子&lt;&#x2F;th&gt;&lt;th&gt;DNSルックアップ&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;ip4&lt;&#x2F;code&gt; &#x2F; &lt;code&gt;ip6&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;0回（IP直接指定のためDNS不要）&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;a&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;1回&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;mx&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;1回（＋MXレコードが指すAレコードの解決）&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;include&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;1回 ＋ 参照先のSPFレコード内のルックアップ&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;redirect&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;1回&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;exists&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;1回&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;重要なのは &lt;code&gt;include&lt;&#x2F;code&gt; の挙動です。&lt;code&gt;include&lt;&#x2F;code&gt; は参照先のSPFレコードをさらに評価するため、参照先に &lt;code&gt;include&lt;&#x2F;code&gt; や &lt;code&gt;a&lt;&#x2F;code&gt; が含まれていれば、それらも合算されます。つまり、1つの &lt;code&gt;include&lt;&#x2F;code&gt; が実際には複数回のルックアップを消費する場合があります。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;includeの入れ子で上限に近づく実例&quot;&gt;includeの入れ子で上限に近づく実例&lt;&#x2F;h2&gt;
&lt;p&gt;架空の組織 &lt;code&gt;example.or.jp&lt;&#x2F;code&gt; を例に考えます。この組織では業務メールに加えて、メールマガジン配信に3つの外部サービスを利用しています。SPFレコードは以下のようになっています。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;v=spf1 ip4:192.0.2.0&#x2F;29 ip4:198.51.100.1 include:spf.mail-a.example include:spf.mail-b.example include:spf.mail-c.example include:spf.bizmail.example ~all&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;各エントリのDNSルックアップ数を確認します。&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;エントリ&lt;&#x2F;th&gt;&lt;th&gt;DNSルックアップ&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;ip4:192.0.2.0&#x2F;29&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;0回（IP直接指定）&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;ip4:198.51.100.1&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;0回（IP直接指定）&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;include:spf.mail-a.example&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;1回&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;include:spf.mail-b.example&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;1回 ＋ 内部で3回 = 4回&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;include:spf.mail-c.example&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;1回&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;include:spf.bizmail.example&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;1回&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;合計&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;td&gt;&lt;strong&gt;7回 &#x2F; 上限10回&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;一見すると余裕がありそうですが、問題は &lt;code&gt;spf.mail-b.example&lt;&#x2F;code&gt; の内部構造です。このSPFレコードは以下のようになっています。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;v=spf1 exists:%{i}.spf.mail-b1.example exists:%{i}.spf.mail-b2.example include:spf.mail-b3.example ~all&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;code&gt;include&lt;&#x2F;code&gt; 1つで4回のルックアップを消費しています。そして、この内訳は外部サービス側の設定に依存しています。&lt;&#x2F;p&gt;
&lt;p&gt;ここに大きなリスクがあります。外部サービスがインフラ変更に伴いSPFレコードへ &lt;code&gt;include&lt;&#x2F;code&gt; や &lt;code&gt;a&lt;&#x2F;code&gt; を追加すれば、自組織が何も変更していなくてもルックアップ数が増加します。たとえば &lt;code&gt;spf.mail-b.example&lt;&#x2F;code&gt; が内部で1つ &lt;code&gt;include&lt;&#x2F;code&gt; を追加するだけで、合計は8回になり、上限までわずか2回です。さらに別のサービスも同様の変更をすれば、上限を超えてしまいます。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;上限を超えるとどうなるか&quot;&gt;上限を超えるとどうなるか&lt;&#x2F;h2&gt;
&lt;p&gt;SPFのルックアップ数が10回を超えると、SPFの検証結果は &lt;code&gt;permerror&lt;&#x2F;code&gt;（恒久的エラー）になります。これは「SPFレコードが壊れている」とみなされる状態です。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;code&gt;permerror&lt;&#x2F;code&gt; が発生すると、受信側メールサーバーの設定に応じて以下のいずれかが起こります。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;メールが拒否される（バウンス）&lt;&#x2F;li&gt;
&lt;li&gt;迷惑メールフォルダに振り分けられる&lt;&#x2F;li&gt;
&lt;li&gt;DMARCのSPF判定がfailとなり、DMARCポリシー次第でメールが拒否される&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;特に厄介なのは、この問題が自組織側からは気づきにくい点です。送信自体は正常に行われ、送信者にはエラーが返らない場合もあります。受信側で静かにスパム判定されるため、「最近メールの返信が来ない」「メルマガの開封率が急落した」といった間接的な兆候で初めて気づくことになります。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;自分のドメインのルックアップ数を確認する方法&quot;&gt;自分のドメインのルックアップ数を確認する方法&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;code&gt;dig&lt;&#x2F;code&gt; コマンドでSPFレコードの内容を確認できます。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;dig&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; +short TXT example.or.jp&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; |&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; grep&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; spf&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;表示されたSPFレコードに含まれる &lt;code&gt;include&lt;&#x2F;code&gt; 先も再帰的に確認する必要があります。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;dig&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; +short TXT spf.mail-b.example&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;手動での再帰的な確認は手間がかかるため、オンラインツールの利用も有効です。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;MXToolbox SPF Record Lookup&lt;&#x2F;strong&gt; — SPFレコードの内容とDNSルックアップ数を自動計算してくれる&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;dmarcian SPF Surveyor&lt;&#x2F;strong&gt; — SPFレコードの構造をツリー表示で可視化できる&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;これらのツールにドメイン名を入力するだけで、現在のルックアップ数と上限までの余裕を確認できます。定期的にチェックしておくことをお勧めします。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;対策&quot;&gt;対策&lt;&#x2F;h2&gt;
&lt;p&gt;SPFルックアップ上限の問題に対して、短期的な対策と中長期的な対策があります。&lt;&#x2F;p&gt;
&lt;p&gt;まず短期的な対策として、メール送信経路を棚卸しします。SPFレコードに登録されている &lt;code&gt;include&lt;&#x2F;code&gt; やIPアドレスが、現在も使われているかを確認します。利用を終了したサービスの &lt;code&gt;include&lt;&#x2F;code&gt; が残っていると、ルックアップ数を無駄に消費するだけでなく、そのサービスのIPレンジが自ドメインの正当な送信元として許可されたままになります。これはなりすましに悪用されるリスクでもあります。&lt;&#x2F;p&gt;
&lt;p&gt;次に、メール配信サービスの統合を検討します。メルマガ配信に複数のサービスを併用している場合、1つに統合すれば &lt;code&gt;include&lt;&#x2F;code&gt; の数を減らせます。配信実績の分析も一元化でき、コスト管理も簡素化されます。&lt;&#x2F;p&gt;
&lt;p&gt;これらの根本対策とは別に、技術的な回避策も存在します&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-spf-workaround-1&quot;&gt;&lt;a href=&quot;#fn-spf-workaround&quot;&gt;1&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;。ただし運用上の注意点があるため、まずは送信経路の整理を優先すべきです。&lt;&#x2F;p&gt;
&lt;p&gt;最後に、中長期的な対策としてDMARCポリシーの段階的強化があります。DMARCはSPFとDKIMの認証結果に基づいて、認証失敗時のメール処理方針を宣言する仕組みです。ポリシーは以下の順で強化します。&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;p=none&lt;&#x2F;code&gt;（監視モード）でDMARCレポートを収集し、全送信経路の認証状況を把握する&lt;&#x2F;li&gt;
&lt;li&gt;全経路でSPF・DKIMがpassすることを確認したうえで &lt;code&gt;p=quarantine&lt;&#x2F;code&gt;（隔離）に移行する&lt;&#x2F;li&gt;
&lt;li&gt;一定期間の監視後、問題がなければ &lt;code&gt;p=reject&lt;&#x2F;code&gt;（拒否）に移行する&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;送信経路が整理されていれば、この移行は技術的には難しくありません。逆に、送信経路が乱立したままでは各経路の認証状況を把握すること自体が困難であり、DMARC強化は事実上不可能です。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;まとめ&quot;&gt;まとめ&lt;&#x2F;h2&gt;
&lt;p&gt;SPFのDNSルックアップ上限10回は、メール配信サービスを複数利用する組織にとって見落とされがちなリスクです。外部サービスの &lt;code&gt;include&lt;&#x2F;code&gt; は入れ子構造でルックアップ数が膨らみ、しかも外部サービス側の変更で自組織のルックアップ数が増加するという、制御しにくい特性があります。&lt;&#x2F;p&gt;
&lt;p&gt;まずは自分のドメインの現在のルックアップ数を確認してみてください。上限に近づいている場合は、不要な &lt;code&gt;include&lt;&#x2F;code&gt; の削除やサービスの統合を検討し、DMARCポリシーの強化と合わせてメール配信の信頼性を確保していくことが重要です。&lt;&#x2F;p&gt;
&lt;section class=&quot;footnotes&quot;&gt;
&lt;ol class=&quot;footnotes-list&quot;&gt;
&lt;li id=&quot;fn-spf-workaround&quot;&gt;
&lt;p&gt;技術的な回避策としてSPF MacroとSPF flatteningがあります。SPF Macroは &lt;code&gt;exists&lt;&#x2F;code&gt; メカニズムと変数を組み合わせてルックアップ数を抑える手法です。SPF flatteningは &lt;code&gt;include&lt;&#x2F;code&gt; 先のIPアドレスを直接 &lt;code&gt;ip4&lt;&#x2F;code&gt; &#x2F; &lt;code&gt;ip6&lt;&#x2F;code&gt; で記述してルックアップを削減する手法です。ただしflatteningは参照先のIPが変更されたときに追従が必要なため、自動化ツールなしでの運用は推奨しません。 &lt;a href=&quot;#fr-spf-workaround-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;&#x2F;section&gt;
</content>
        <summary type="html">SPFにはDNSルックアップ上限10回の制約があり、外部メール配信サービスのincludeが入れ子で膨らむと意図せず超過するリスクがあります。上限超過の仕組みと確認方法、対策を解説します。</summary>
        </entry><entry xml:lang="en">
        <title>CLS改善のためにZolaの画像ショートコードを自作した</title>
        <published>2026-03-01T06:35:31+09:00</published>
        <updated>2026-03-01T06:35:31+09:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2026/03/zola-robust-image-shortcode/" type="text/html"/>
        <id>https://codedchords.dev/blog/2026/03/zola-robust-image-shortcode/</id>
        
            <content type="html">&lt;details&gt;
&lt;summary&gt;Table of Contents&lt;&#x2F;summary&gt;
&lt;!-- toc --&gt;
&lt;&#x2F;details&gt;
&lt;h2 id=&quot;CLSとは&quot;&gt;CLSとは&lt;&#x2F;h2&gt;
&lt;p&gt;Cloudflare Pagesにブログを移行したことで、Cloudflare Web Analyticsが利用できるようになりました。アクセス数だけでなくCore Web Vitalsの各指標も確認できるのですが、そのなかでCLS（Cumulative Layout Shift）のスコアが気になる結果でした。&lt;&#x2F;p&gt;
&lt;!-- textlint-disable --&gt;
&lt;figure&gt;&lt;img
  src=&quot;https:&amp;#x2F;&amp;#x2F;codedchords.dev&amp;#x2F;blog&amp;#x2F;2026&amp;#x2F;03&amp;#x2F;zola-robust-image-shortcode&amp;#x2F;cls.webp?h=a3143d5feda5b00f4198&quot;
  alt=&quot;CLS&quot; width=&quot;733&quot; height=&quot;621&quot; loading=&quot;lazy&quot;
&#x2F;&gt;
&lt;figcaption&gt;Cloudflare Web Analytics画面&lt;&#x2F;figcaption&gt;
&lt;&#x2F;figure&gt;&lt;!-- textlint-enable --&gt;
&lt;p&gt;Core Web VitalsはGoogleが提唱するWebページのユーザー体験を測定する指標群で、LCP（Largest Contentful Paint：読み込み速度）、INP（Interaction to Next Paint：応答性）、CLS（Cumulative Layout Shift：視覚的安定性）の3つで構成されます。いずれもGoogleの検索ランキングに影響するため、サイト運営者にとって無視できない指標です。&lt;&#x2F;p&gt;
&lt;p&gt;CLSはページの読み込み中にコンテンツが予期せずずれる現象を数値化したもので、0.1以下が「良好」とされています。CLSが悪化する代表的な原因は、画像や広告などの要素にサイズ（&lt;code&gt;width&lt;&#x2F;code&gt;と&lt;code&gt;height&lt;&#x2F;code&gt;）が指定されていないことです。サイズが未指定の画像は、読み込まれるまでブラウザが表示領域を確保できません。画像の読み込みが完了した瞬間にページ全体がガクッとずれてしまい、ユーザーが読んでいた箇所を見失うことになります。&lt;&#x2F;p&gt;
&lt;p&gt;私のブログを調べてみると、ほぼすべての記事画像に&lt;code&gt;width&lt;&#x2F;code&gt;と&lt;code&gt;height&lt;&#x2F;code&gt;が設定されていませんでした。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;画像要素の改善&quot;&gt;画像要素の改善&lt;&#x2F;h2&gt;
&lt;p&gt;このブログは静的サイトジェネレーターのZolaを使用しており、記事はMarkdownで書いています。Markdownの画像記法は以下のとおりですが、&lt;code&gt;width&lt;&#x2F;code&gt;や&lt;code&gt;height&lt;&#x2F;code&gt;などのメタ情報を記述する手段がありません&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-1-1&quot;&gt;&lt;a href=&quot;#fn-1&quot;&gt;1&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;markdown&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-link&quot;&gt;![&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;カバー画像&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-link&quot;&gt;]&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-markup z-underline z-link&quot;&gt;cover.jpg&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;そこでZolaのショートコードを利用して、画像サイズなどのメタ情報を自動でセットする仕組みを作りました。以下はコードの抜粋です。&lt;&#x2F;p&gt;
&lt;!-- textlint-disable --&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;html&quot; data-name=&quot;templates&#x2F;shortcodes&#x2F;image.html&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;        This supports the co-location pattern where content and&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;        assets live in the same directory. -#}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;    {%- set colocated_path = page.colocated_path | default(value=&amp;quot;&amp;quot;) -%}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;    {%- set resolved_path = colocated_path ~ src -%}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;    {%- set meta = get_image_metadata(path=resolved_path, allow_missing=true) -%}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;    {%- if meta -%}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;!-- textlint-enable --&gt;
&lt;p&gt;Zolaの&lt;code&gt;get_image_metadata&lt;&#x2F;code&gt;関数はビルド時に画像ファイルを読み取り、幅と高さを返してくれます。これを利用して&lt;code&gt;width&lt;&#x2F;code&gt;と&lt;code&gt;height&lt;&#x2F;code&gt;を&lt;code&gt;img&lt;&#x2F;code&gt;要素に指定しています。あわせて&lt;code&gt;get_url&lt;&#x2F;code&gt;関数の&lt;code&gt;cachebust=true&lt;&#x2F;code&gt;オプションでファイルのハッシュ値をURLに付与し、キャッシュバスティングにも対応しました。&lt;&#x2F;p&gt;
&lt;p&gt;あとはHTMLの&lt;code&gt;img&lt;&#x2F;code&gt;要素として画像サイズが出力されるように組み立てるだけです。&lt;&#x2F;p&gt;
&lt;!-- textlint-disable --&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;html&quot; data-name=&quot;templates&#x2F;shortcodes&#x2F;image.html&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;  {%- if meta and meta.width %} width=&amp;quot;{{ meta.width }}&amp;quot;{% endif %}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;  {%- if meta and meta.height %} height=&amp;quot;{{ meta.height }}&amp;quot;{% endif %}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;  {%- if lazy_loading %} loading=&amp;quot;lazy&amp;quot;{% endif %}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;&#x2F;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;{%- if link_to_self %}&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;a&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt;{% endif %}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;figcaption&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt;{{ caption_text }}&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;figcaption&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;figure&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;!-- textlint-enable --&gt;
&lt;p&gt;この結果、記事には以下のように書くだけで、画像サイズとキャッシュバスティングに対応した&lt;code&gt;img&lt;&#x2F;code&gt;要素を自動出力できるようになりました。&lt;&#x2F;p&gt;
&lt;!-- textlint-disable --&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;markdown&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;{{ image(src=&amp;quot;cover.jpg&amp;quot;, alt=&amp;quot;カバー画像&amp;quot;) }}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;!-- textlint-enable --&gt;
&lt;p&gt;Zola依存にはなりますが、記述を複雑にせずCLS対策ができました。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;figure対応&quot;&gt;figure対応&lt;&#x2F;h2&gt;
&lt;p&gt;記事内の画像にキャプションを付けたい場合もあります。そこで&lt;code&gt;caption&lt;&#x2F;code&gt;パラメータが指定された場合には、&lt;code&gt;img&lt;&#x2F;code&gt;要素を&lt;code&gt;figure&lt;&#x2F;code&gt;要素で囲み、&lt;code&gt;figcaption&lt;&#x2F;code&gt;要素でキャプションを出力するようにしました。&lt;code&gt;caption&lt;&#x2F;code&gt;を省略した場合は従来どおり&lt;code&gt;img&lt;&#x2F;code&gt;要素のみを出力します。&lt;&#x2F;p&gt;
&lt;p&gt;以下がショートコードの全容です。&lt;&#x2F;p&gt;
&lt;details&gt;
  &lt;summary&gt;imageショートコード&lt;&#x2F;summary&gt;
&lt;!-- textlint-disable --&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;html&quot; data-name=&quot;templates&#x2F;shortcodes&#x2F;image.html&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;{#- ============================================================&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;    image.html - Image shortcode for Zola&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;    Copyright (c) 2026 Toshiyuki Yoshida&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;    Released under the MIT License.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;    https:&#x2F;&#x2F;opensource.org&#x2F;licenses&#x2F;MIT&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;     Repository: https:&#x2F;&#x2F;github.com&#x2F;yostos&#x2F;blog-yostos&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;    Renders an &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;img&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt; tag with automatic path resolution,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;    image metadata (width&#x2F;height), cache busting, and lazy loading.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;    Parameters:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;      src          - Image path or remote URL (required)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;      alt          - Alt text for accessibility (recommended)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;      caption      - Caption text displayed below the image (optional)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;                     When specified, wraps output in &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;figure&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;figcaption&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;      lazy_loading - Enable lazy loading (default: true)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;      link_to_self - Wrap the image in a link to the image file itself,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;                     opening in a new tab (default: false)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;    ============================================================ -#}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;{#- Strip leading &amp;quot;.&#x2F;&amp;quot; from src to normalize colocated paths&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;    e.g. &amp;quot;.&#x2F;photo.jpg&amp;quot; -&amp;gt; &amp;quot;photo.jpg&amp;quot; -#}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;{%- set src = src | trim_start_matches(pat=&amp;quot;.&#x2F;&amp;quot;) -%}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;{#- ---- URL resolution ---- -#}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;{%- if src is starting_with(&amp;quot;http&amp;quot;) -%}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;    {#- Remote image: use src as-is. Metadata cannot be retrieved&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;        for external URLs, so width&#x2F;height will not be set. -#}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;    {%- set image_url = src -%}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;{%- else -%}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;    {#- Local image: first try resolving relative to the page&amp;#39;s&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;        colocated directory (e.g. content&#x2F;blog&#x2F;my-post&#x2F;photo.jpg).&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;        This supports the co-location pattern where content and&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;        assets live in the same directory. -#}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;    {%- set colocated_path = page.colocated_path | default(value=&amp;quot;&amp;quot;) -%}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;    {%- set resolved_path = colocated_path ~ src -%}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;    {%- set meta = get_image_metadata(path=resolved_path, allow_missing=true) -%}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;    {%- if meta -%}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;        {#- Colocated path resolved successfully -#}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;        {%- set image_url = get_url(path=resolved_path, cachebust=true) -%}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;    {%- else -%}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;        {#- Fallback: treat src as an absolute path from the project root.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;            This handles images placed under the static&#x2F; directory,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;            e.g. src=&amp;quot;&#x2F;images&#x2F;shared.jpg&amp;quot; -#}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;        {%- set meta = get_image_metadata(path=src, allow_missing=true) -%}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;        {%- if meta -%}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;            {%- set image_url = get_url(path=src, cachebust=true) -%}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;        {%- else -%}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;            {#- Neither path worked. Output the URL anyway so the page&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;                does not break, but width&#x2F;height will be omitted.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;                This may indicate a missing or misspelled image path. -#}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;            {%- set image_url = get_url(path=src, cachebust=true) -%}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;        {%- endif -%}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;    {%- endif -%}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;{%- endif -%}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;{#- ---- Attribute defaults ---- -#}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;{#- Default alt to empty string so the attribute is always present.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;    An explicit alt=&amp;quot;&amp;quot; is valid for decorative images and is preferred&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;    over omitting the attribute entirely for accessibility. -#}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;{%- set alt_text = alt | default(value=&amp;quot;&amp;quot;) -%}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;{#- Lazy loading is enabled by default for better page performance -#}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;{%- set lazy_loading = lazy_loading | default(value=true) -%}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;{#- Caption: when specified, wrap in &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;figure&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;figcaption&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt; -#}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;{%- set caption_text = caption | default(value=&amp;quot;&amp;quot;) -%}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;{#- When enabled, wrap the image in a link to the image file itself,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;    opening in a new tab so the full-size image can be viewed alone. -#}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;{%- set link_to_self = link_to_self | default(value=false) -%}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;{#- ---- Output ---- -#}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;{%- if caption_text -%}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;figure&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;{%- if link_to_self %}&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;a&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-other z-attribute-name&quot;&gt; href&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;{{ image_url }}&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-other z-attribute-name&quot;&gt; target&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;_blank&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-other z-attribute-name&quot;&gt; rel&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;noopener&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt;{% endif -%}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;img&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-other z-attribute-name&quot;&gt;  src&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;{{ image_url }}&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-other z-attribute-name&quot;&gt;  alt&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;{{ alt_text }}&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-other z-attribute-name&quot;&gt;  {%- if meta and meta.width %} width&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;{{ meta.width }}&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-other z-attribute-name&quot;&gt;{% endif %}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-other z-attribute-name&quot;&gt;  {%- if meta and meta.height %} height&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;{{ meta.height }}&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-other z-attribute-name&quot;&gt;{% endif %}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-other z-attribute-name&quot;&gt;  {%- if lazy_loading %} loading&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;lazy&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-other z-attribute-name&quot;&gt;{% endif %}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&#x2F;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;{%- if link_to_self %}&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;a&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt;{% endif %}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;figcaption&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt;{{ caption_text }}&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;figcaption&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;figure&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;{%- else -%}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;{%- if link_to_self %}&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;a&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-other z-attribute-name&quot;&gt; href&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;{{ image_url }}&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-other z-attribute-name&quot;&gt; target&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;_blank&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-other z-attribute-name&quot;&gt; rel&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;noopener&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt;{% endif -%}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;img&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-other z-attribute-name&quot;&gt;  src&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;{{ image_url }}&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-other z-attribute-name&quot;&gt;  alt&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;{{ alt_text }}&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-other z-attribute-name&quot;&gt;  {%- if meta and meta.width %} width&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;{{ meta.width }}&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-other z-attribute-name&quot;&gt;{% endif %}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-other z-attribute-name&quot;&gt;  {%- if meta and meta.height %} height&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;{{ meta.height }}&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-other z-attribute-name&quot;&gt;{% endif %}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-other z-attribute-name&quot;&gt;  {%- if lazy_loading %} loading&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;lazy&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-other z-attribute-name&quot;&gt;{% endif %}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&#x2F;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;{%- if link_to_self %}&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;a&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt;{% endif -%}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;{%- endif -%}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;  &lt;!-- textlint-enable --&gt;
&lt;&#x2F;details&gt;
&lt;h2 id=&quot;References&quot;&gt;References&lt;&#x2F;h2&gt;
&lt;!-- textlint-disable --&gt;
&lt;div class=&quot;references&quot;&gt;
    &lt;ul&gt;
&lt;li&gt;web.dev. 「&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;web.dev&#x2F;articles&#x2F;cls&quot;&gt;Cumulative Layout Shift (CLS)&lt;&#x2F;a&gt;」&lt;&#x2F;li&gt;
&lt;li&gt;web.dev. 「&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;web.dev&#x2F;articles&#x2F;vitals&quot;&gt;Core Web Vitals&lt;&#x2F;a&gt;」&lt;&#x2F;li&gt;
&lt;li&gt;Zola. &quot;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.getzola.org&#x2F;documentation&#x2F;content&#x2F;shortcodes&#x2F;&quot;&gt;Shortcodes&lt;&#x2F;a&gt;&quot;&lt;&#x2F;li&gt;
&lt;li&gt;Zola. &quot;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.getzola.org&#x2F;documentation&#x2F;templates&#x2F;overview&#x2F;#get-image-metadata&quot;&gt;Overview - get_image_metadata&lt;&#x2F;a&gt;&quot;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;

&lt;&#x2F;div&gt;
&lt;!-- textlint-enable --&gt;
&lt;section class=&quot;footnotes&quot;&gt;
&lt;ol class=&quot;footnotes-list&quot;&gt;
&lt;li id=&quot;fn-1&quot;&gt;
&lt;p&gt;ZolaはCommonMarkをベースとしたpulldown-cmarkというRustのライブラリ
を使用しているため画像にメタ情報を付与できませんが、Markdownの処理系によっては記述可能なものも存在します。 &lt;a href=&quot;#fr-1-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;&#x2F;section&gt;
</content>
        <summary type="html">Zolaで構築したブログのCLS（Cumulative Layout Shift）を改善するため、画像サイズを自動取得するショートコードを作成しました。実装の詳細と、caption対応によるfigure要素の出力まで解説します。</summary>
        </entry><entry xml:lang="en">
        <title>ZolaブログにPagefindで日本語検索を導入した</title>
        <published>2026-02-26T07:58:30+09:00</published>
        <updated>2026-02-26T07:58:30+09:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2026/02/zola-pagefind-search/" type="text/html"/>
        <id>https://codedchords.dev/blog/2026/02/zola-pagefind-search/</id>
        
            <content type="html">&lt;h2 id=&quot;はじめに（Zolaの検索事情）&quot;&gt;はじめに（Zolaの検索事情）&lt;&#x2F;h2&gt;
&lt;p&gt;このブログも記事数が255を超え、
検索機能なしでは目的の記事に
たどり着きにくくなってきました。
タグやアーカイブで絞り込めはしますが、
「あのキーワードで書いた記事どこだっけ」
という場面には対応できません。&lt;&#x2F;p&gt;
&lt;p&gt;このブログで使用している静的サイトジェネレーター
Zolaには検索機能が組み込まれています。
検索エンジンには
&lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;elasticlunr.com&#x2F;&quot;&gt;elasticlunr.js&lt;&#x2F;a&gt;
が使われていますが、
日本語のトークナイズに対応していません。
elasticlunr自体が長期間更新されておらず、
今後の対応も期待できない状況です。&lt;&#x2F;p&gt;
&lt;p&gt;適用しているテーマ
&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;welpo&#x2F;tabi&quot;&gt;tabi&lt;&#x2F;a&gt;
の検索UIもelasticlunrを前提としており、
日本語ブログでは実質的に使えません。
&lt;code&gt;config.toml&lt;&#x2F;code&gt;では&lt;code&gt;build_search_index = false&lt;&#x2F;code&gt;
として無効化していました。&lt;&#x2F;p&gt;
&lt;p&gt;そこで、日本語対応の検索機能を導入することにしました。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;検索エンジンの選定&quot;&gt;検索エンジンの選定&lt;&#x2F;h2&gt;
&lt;p&gt;静的サイトで使える検索エンジンを
いくつか比較検討しましたが、
下表のような理由で見送りました。&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;候補&lt;&#x2F;th&gt;&lt;th&gt;見送った理由&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;Algolia&lt;&#x2F;td&gt;&lt;td&gt;SaaS依存。無料枠に月10,000リクエスト制限。検索クエリが外部に送信される&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Meilisearch&lt;&#x2F;td&gt;&lt;td&gt;サーバーの常時稼働が必要で、静的サイトとは根本的に合わない&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Fuse.js&lt;&#x2F;td&gt;&lt;td&gt;全インデックスをクライアントにダウンロードする設計。記事数の増加に弱い&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Google PSE&lt;&#x2F;td&gt;&lt;td&gt;無料版は広告表示あり。サービス縮小傾向。プライバシーの懸念&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;最終的に選定したのは、&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;pagefind.app&#x2F;&quot;&gt;Pagefind&lt;&#x2F;a&gt;
です。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;Pagefind_とは&quot;&gt;Pagefind とは&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;pagefind.app&#x2F;&quot;&gt;Pagefind&lt;&#x2F;a&gt;は
CloudCannonが開発した静的サイト向けの
全文検索ライブラリです。&lt;&#x2F;p&gt;
&lt;p&gt;サイトのビルド後にHTMLを解析して
検索インデックスを静的ファイルとして生成し、
検索時にはWebAssemblyで動作する
クライアントサイドの検索エンジンが
必要なチャンクだけを読み込んで結果を返します。
外部サーバーへの通信は一切発生しません。&lt;&#x2F;p&gt;
&lt;!-- textlint-disable --&gt;
&lt;aside data-position=&quot;right&quot;&gt;
    &lt;p&gt;セグメンテーションとは、
文章を単語に分割する処理。
英語のように単語がスペースで
区切られていない日本語・中国語・韓国語は
単語を区切る処理が必要。&lt;&#x2F;p&gt;

&lt;&#x2F;aside&gt;
&lt;!-- textlint-enable --&gt;
&lt;p&gt;Extended版ではCJK（中国語・日本語・韓国語）の
セグメンテーションに対応しており、
&lt;code&gt;npx pagefind&lt;&#x2F;code&gt;を実行するだけで
Extended版が自動的にダウンロードされます。
検索UIコンポーネントも同梱されているため、
数行のHTMLを追加するだけで
検索ページを構築できます。&lt;&#x2F;p&gt;
&lt;!-- textlint-disable --&gt;
&lt;div class=&quot;admonition note&quot;&gt;
    &lt;div class=&quot;admonition-icon admonition-icon-note&quot;&gt;&lt;&#x2F;div&gt;
    &lt;div class=&quot;admonition-content&quot;&gt;
        &lt;strong class=&quot;admonition-title&quot;&gt;Note&lt;&#x2F;strong&gt;
        &lt;p&gt;PagefindのセグメンテーションはMeCabのような
品詞分解を行う形態素解析ではなく、
Unicode標準に基づく単語境界の検出です。
そのため「走る」で「走った」がヒットするような
活用形の展開（ステミング）には対応していません。&lt;&#x2F;p&gt;

    &lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;!-- textlint-enable --&gt;
&lt;p&gt;このブログでPagefindを採用した
決め手は次の点です。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;日本語対応&lt;&#x2F;strong&gt;:
Extended版がCJKセグメンテーションに対応している&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;静的サイトとの親和性&lt;&#x2F;strong&gt;:
ビルド時にインデックスを静的ファイルとして生成する。
外部サービスが不要&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;軽量&lt;&#x2F;strong&gt;:
インデックスはチャンク分割され、
検索時に必要な部分だけが転送される&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;プライバシー&lt;&#x2F;strong&gt;:
完全にクライアントサイドで動作する。
このブログの
設計思想とも一致する&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;コスト&lt;&#x2F;strong&gt;: ゼロ&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;実装のアプローチ&quot;&gt;実装のアプローチ&lt;&#x2F;h2&gt;
&lt;p&gt;tabiテーマにはできるだけ手を入れない
方針を採りました。
テーマを直接編集すると、
アップデートのたびに変更が衝突して
追従が面倒になるためです。
Zolaでは&lt;code&gt;templates&#x2F;&lt;&#x2F;code&gt;に同名のファイルを
置くことでテーマのテンプレートを
上書きでき、CSSも&lt;code&gt;static&#x2F;custom.css&lt;&#x2F;code&gt;で
追記できます。&lt;&#x2F;p&gt;
&lt;p&gt;tabiの検索UIは&lt;code&gt;build_search_index = true&lt;&#x2F;code&gt;
のときにだけ表示される仕組みです。
Pagefindは独自のUIコンポーネントを持っているため、
tabiの検索モーダルは使わず、
Pagefind UIを載せた専用の検索ページを
新設する方式にしました。
ナビゲーションメニューに「search」を
追加し、読者はそこから検索を利用します。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;Pagefindの実装&quot;&gt;Pagefindの実装&lt;&#x2F;h2&gt;
&lt;!-- author-approved: Pagefindの実装セクション配下の分類に必要 --&gt;
&lt;h3 id=&quot;実装概要&quot;&gt;実装概要&lt;&#x2F;h3&gt;
&lt;p&gt;まずPagefindをインストールします。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;npm&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; install -D pagefind&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;次にプロジェクトルートにPagefindの設定ファイル
&lt;code&gt;pagefind.yml&lt;&#x2F;code&gt;を作成します。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;yaml&quot; data-name=&quot;pagefind.yml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;site&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; public&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;glob&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;blog&#x2F;**&#x2F;*.html&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;force_language&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; ja&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;code&gt;glob&lt;&#x2F;code&gt;でインデックス対象を&lt;code&gt;blog&#x2F;&lt;&#x2F;code&gt;配下の
記事に限定し、トップページやaboutなどの
固定ページは除外しています。
&lt;code&gt;force_language: ja&lt;&#x2F;code&gt;は
日本語のCJKセグメンテーションを強制する設定です。&lt;&#x2F;p&gt;
&lt;p&gt;検索ページはZolaのセクションとして作成します。
&lt;code&gt;content&#x2F;search&#x2F;_index.md&lt;&#x2F;code&gt;でテンプレートを指定し、
&lt;code&gt;templates&#x2F;search.html&lt;&#x2F;code&gt;にPagefind UIを配置します。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;html&quot; data-name=&quot;templates&#x2F;search.html&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;{% extends &amp;quot;base.html&amp;quot; %}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;{% block main_content %}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;main&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;  &amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;div&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-other z-attribute-name&quot;&gt; class&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;wide-container&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;    &amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;link&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-other z-attribute-name&quot;&gt;      href&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;&#x2F;pagefind&#x2F;pagefind-ui.css&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-other z-attribute-name&quot;&gt;      rel&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;stylesheet&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;    &#x2F;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;    &amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;div&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-other z-attribute-name&quot;&gt; id&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;search&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;gt;&amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;div&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;    &amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;script&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-other z-attribute-name&quot;&gt;      src&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;&#x2F;pagefind&#x2F;pagefind-ui.js&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;    &amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;script&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;    &amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;script&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;      window&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;addEventListener&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;        &amp;#39;DOMContentLoaded&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;, ()&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt; =&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-new&quot;&gt;        new&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; PagefindUI&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;          element&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;#search&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;          showSubResults&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language z-boolean&quot;&gt; true&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;          showImages&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language z-boolean&quot;&gt; false&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;          translations&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;            placeholder&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;              &amp;quot;検索キーワードを入力…&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;            zero_results&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;              &amp;quot;[SEARCH_TERM] の検索結果は&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;              +&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;ありません&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;            one_result&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;              &amp;quot;[SEARCH_TERM] の検索結果: 1件&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;            many_results&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;              &amp;quot;[COUNT] 件の検索結果&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;            clear_search&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;クリア&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;          }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;        }&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;      }&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    &amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;script&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;  &amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;div&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;main&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;{% endblock main_content %}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;tabiの&lt;code&gt;base.html&lt;&#x2F;code&gt;を継承することで、
ヘッダーやフッター、
スキンの設定がそのまま反映されます。
&lt;code&gt;translations&lt;&#x2F;code&gt;で検索UIの
日本語メッセージを指定しています。&lt;&#x2F;p&gt;
&lt;!-- author-approved: Pagefindの実装セクション配下の分類に必要 --&gt;
&lt;h3 id=&quot;minify_htmlの罠&quot;&gt;minify_htmlの罠&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;code&gt;zola build&lt;&#x2F;code&gt;後にPagefindを実行したところ、
304個のHTMLファイルを検出しながら
インデックスされたページは0件、
「Discovered 0 languages」という
結果になりました。&lt;&#x2F;p&gt;
&lt;p&gt;原因の切り分けは次のように進めました。&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;最小限のHTMLファイルを作成して
Pagefindを実行 → 正常動作&lt;&#x2F;li&gt;
&lt;li&gt;Zolaが実際に生成したHTMLをコピーして
Pagefindを実行 → 再現&lt;&#x2F;li&gt;
&lt;li&gt;HTMLの要素を削りながら比較
→ &lt;code&gt;&amp;lt;&#x2F;head&amp;gt;&lt;&#x2F;code&gt;の有無で結果が変わることを特定&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;Zolaの&lt;code&gt;config.toml&lt;&#x2F;code&gt;で&lt;code&gt;minify_html = true&lt;&#x2F;code&gt;を
設定すると、HTML5の仕様上省略可能な
&lt;code&gt;&amp;lt;&#x2F;head&amp;gt;&lt;&#x2F;code&gt;閉じタグが除去されます。
これ自体はHTML5として合法ですが、
Pagefind v1.4.0のHTMLパーサーは
&lt;code&gt;&amp;lt;&#x2F;head&amp;gt;&lt;&#x2F;code&gt;がないとページを正しく解析できず、
言語検出に失敗していました。&lt;&#x2F;p&gt;
&lt;p&gt;このブログの規模ではHTML minifyの
恩恵は無視できるため、
&lt;code&gt;config.toml&lt;&#x2F;code&gt;で&lt;code&gt;minify_html = false&lt;&#x2F;code&gt;に
変更して対処しました。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;toml&quot; data-name=&quot;config.toml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;minify_html&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language z-boolean&quot;&gt; false&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;これはZolaの不具合ではなく
Pagefindのパーサー側の制約です。
将来Pagefindが&lt;code&gt;&amp;lt;&#x2F;head&amp;gt;&lt;&#x2F;code&gt;省略に
対応すれば&lt;code&gt;minify_html&lt;&#x2F;code&gt;を
再度有効化できます。&lt;&#x2F;p&gt;
&lt;!-- author-approved: Pagefindの実装セクション配下の分類に必要 --&gt;
&lt;h3 id=&quot;テーマとの共存で踏んだCSS問題&quot;&gt;テーマとの共存で踏んだCSS問題&lt;&#x2F;h3&gt;
&lt;p&gt;Pagefind UIにはCSS Custom Propertiesで
スタイルをカスタマイズする仕組みがあります。
テーマカラーに合わせるため
&lt;code&gt;:root&lt;&#x2F;code&gt;で変数を宣言したところ、
期待どおりに適用されませんでした。&lt;&#x2F;p&gt;
&lt;p&gt;原因はCSSのカスケード順序にあります。
&lt;code&gt;pagefind-ui.css&lt;&#x2F;code&gt;は検索ページの&lt;code&gt;&amp;lt;main&amp;gt;&lt;&#x2F;code&gt;内で
読み込まれるため、tabiが&lt;code&gt;&amp;lt;head&amp;gt;&lt;&#x2F;code&gt;内で
読み込む&lt;code&gt;custom.css&lt;&#x2F;code&gt;よりも後にカスケードされます。
結果として、Pagefindのデフォルト値が
こちらの&lt;code&gt;:root&lt;&#x2F;code&gt;宣言に勝っていました。&lt;&#x2F;p&gt;
&lt;p&gt;セレクタを&lt;code&gt;.pagefind-ui&lt;&#x2F;code&gt;に変更し、
クラスセレクタの詳細度で
確実にオーバーライドするようにしました。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;css&quot; data-name=&quot;static&#x2F;custom.css&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-other z-attribute-name z-class z-css&quot;&gt;pagefind-ui&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable&quot;&gt;  --pagefind-ui-primary&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-function z-misc&quot;&gt;    var&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt;--primary-color&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable&quot;&gt;  --pagefind-ui-text&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-function z-misc&quot;&gt;    var&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt;--text-color&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable&quot;&gt;  --pagefind-ui-background&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-function z-misc&quot;&gt;    var&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt;--background-color&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable&quot;&gt;  --pagefind-ui-border&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-function z-misc&quot;&gt;    var&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt;--divider-color&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable&quot;&gt;  --pagefind-ui-tag&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-misc&quot;&gt; var&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt;--bg-0&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable&quot;&gt;  --pagefind-ui-font&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-function z-misc&quot;&gt;    var&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt;--sans-serif-font&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;tabiの既存のCSS変数を参照することで、
ダークモードやevangelionスキンの
カラースキームに自動で追従します。&lt;&#x2F;p&gt;
&lt;p&gt;もうひとつ、tabiテーマは全リンクに対して
&lt;code&gt;a:hover { background-color: var(--primary-color) }&lt;&#x2F;code&gt;
を適用するグローバルスタイルを持っています。
Pagefindの検索結果は&lt;code&gt;&amp;lt;a&amp;gt;&lt;&#x2F;code&gt;タグで構成されるため、
ホバーするとevangelionスキンの赤
（&lt;code&gt;#d12e36&lt;&#x2F;code&gt;）が結果全体の背景に
適用されてしまいました。&lt;&#x2F;p&gt;
&lt;p&gt;検索結果エリア内のリンクスタイルを個別に
上書きして解消しています。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;css&quot; data-name=&quot;static&#x2F;custom.css&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-other z-attribute-name z-class z-css&quot;&gt;pagefind-ui&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt; a&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-other z-attribute-name z-pseudo-class&quot;&gt;hover&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-other z-attribute-name z-class z-css&quot;&gt;pagefind-ui&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt; a&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-other z-attribute-name z-pseudo-class&quot;&gt;focus&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-type z-property-name z-css&quot;&gt;  background-color&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; transparent&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-type z-property-name z-css&quot;&gt;  color&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-misc&quot;&gt; var&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt;--primary-color&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;CI&#x2F;CDへの組み込み&quot;&gt;CI&#x2F;CDへの組み込み&lt;&#x2F;h2&gt;
&lt;p&gt;このブログはGitHub Actionsで
Cloudflare Workersにデプロイしています。
ワークフローに検索インデックス生成の
ステップを追加しました。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;yaml&quot; data-name=&quot;.github&#x2F;workflows&#x2F;deploy.yml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;-&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt; name&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; Build&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;  run&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; zola build&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;-&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt; name&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; Build search index&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;  run&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; npx pagefind&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;code&gt;zola build&lt;&#x2F;code&gt; → &lt;code&gt;npx pagefind&lt;&#x2F;code&gt;の
2ステップだけで完結します。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;まとめ&quot;&gt;まとめ&lt;&#x2F;h2&gt;
&lt;p&gt;Pagefindの導入により、
303ページ（セクションページ含む）・
17,217語のインデックスが生成され、
日本語キーワードでの検索が
機能するようになりました。&lt;&#x2F;p&gt;
&lt;p&gt;実装自体はシンプルでしたが、
&lt;code&gt;minify_html&lt;&#x2F;code&gt;によるHTML構造の変化や
テーマとのCSS競合など、
組み合わせ固有の問題に時間を取られました。
単独では正しく動くものが
組み合わせると壊れるパターンは、
静的サイトのツールチェーンでは
よくある話かもしれません。&lt;&#x2F;p&gt;
&lt;p&gt;現時点での制約として、
日本語のステミングには未対応です。
「走る」で検索しても
「走った」はヒットしません。
ただし単語単位の検索は安定しており、
現在の規模では実用上十分です。&lt;&#x2F;p&gt;
</content>
        <summary type="html">静的サイトジェネレーターZolaで運用しているこのブログに、
Pagefindを使った日本語対応のサイト内検索を導入しました。
選定の経緯から実装時のハマりどころまでを記録します。
</summary>
        </entry><entry xml:lang="en">
        <title>Zolaテーマ「tabi」の活用機能を探る</title>
        <published>2026-02-24T12:00:00+09:00</published>
        <updated>2026-02-24T12:00:00+09:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2026/02/zola-theme-tabi/" type="text/html"/>
        <id>https://codedchords.dev/blog/2026/02/zola-theme-tabi/</id>
        
            <content type="html">&lt;!-- author-approved: ショートコード名・設定項目の列挙に###を使用 --&gt;
&lt;p&gt;このブログはZola静的サイトジェネレーターと
&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;welpo.github.io&#x2F;tabi&#x2F;&quot;&gt;tabi&lt;&#x2F;a&gt;テーマで
運用しています。
tabiは多機能なテーマですが、
実際に活用しているのはその一部に過ぎません。
改めてテーマの全機能を棚卸しして、
まだ使っていない機能を洗い出してみました。&lt;&#x2F;p&gt;
&lt;details&gt;
&lt;summary&gt;Table of Contents&lt;&#x2F;summary&gt;
&lt;!-- toc --&gt;
&lt;&#x2F;details&gt;
&lt;h2 id=&quot;ショートコード&quot;&gt;ショートコード&lt;&#x2F;h2&gt;
&lt;p&gt;tabiには18種類のビルトインショートコードと、
このブログ用に自作したカスタムショートコード
2種類があります
（カスタムコードは当然ながらtabiには
含まれません）。&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;ショートコード&lt;&#x2F;th&gt;&lt;th&gt;説明&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;admonition&lt;&#x2F;td&gt;&lt;td&gt;info、warning、tipなどのタイプを指定して、注意書きや補足情報を装飾付きボックスで表示します&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;add_src_to_code_block（非推奨）&lt;&#x2F;td&gt;&lt;td&gt;コードブロックの &lt;code&gt;name=&lt;&#x2F;code&gt; ラベルをクリック可能なリンクに変換します。現在は &lt;code&gt;code_block_name_links = true&lt;&#x2F;code&gt; を設定し、&lt;code&gt;name=&lt;&#x2F;code&gt; にURLを直接書く方式が推奨されています&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;aside&lt;&#x2F;td&gt;&lt;td&gt;本文の横にサイドバー風の補足情報を表示します。admonitionより控えめな見た目で、ちょっとした注釈を添えるのに向いています&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;dimmable_image&lt;&#x2F;td&gt;&lt;td&gt;ダークモード時に画像の明るさを自動的に抑えます。白背景のスクリーンショットがダークモードで眩しくなるのを防げます&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;dual_theme_image&lt;&#x2F;td&gt;&lt;td&gt;ライトモードとダークモードで異なる画像を自動的に切り替えて表示します。背景色によって見えにくくなる図表に便利です&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;force_text_direction&lt;&#x2F;td&gt;&lt;td&gt;テキストブロックのLTR（左から右）またはRTL（右から左）の方向を強制的に指定します&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;full_width_image&lt;&#x2F;td&gt;&lt;td&gt;記事の本文幅を超えて、画像をページ全幅で表示します&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;iine&lt;&#x2F;td&gt;&lt;td&gt;特定のブロック単位でいいねボタンを設置できます。tabiの作者が提供するSupabaseインスタンスにカウントが記録されます。導入時はプライバシーポリシーの更新を検討してください&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;image_hover&lt;&#x2F;td&gt;&lt;td&gt;マウスホバーで別の画像に切り替わります。Before&#x2F;After比較や加工前後の写真を見比べるのに最適です&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;image_toggler&lt;&#x2F;td&gt;&lt;td&gt;クリックで2枚の画像をトグル切り替えします。image_hoverと似ていますが、ホバーが使えないモバイル環境でも動作します&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;invertible_image&lt;&#x2F;td&gt;&lt;td&gt;ダークモード時に画像の色を反転します。白背景に黒線で描かれた図表をダークモードでも見やすくできます&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;linkcard（自作）&lt;&#x2F;td&gt;&lt;td&gt;はてなブログカードのiframeを使い、URLをカード形式で表示します&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;mermaid&lt;&#x2F;td&gt;&lt;td&gt;Mermaid記法でフローチャートやシーケンス図などの図表を描画します。記事のFrontmatterで &lt;code&gt;mermaid = true&lt;&#x2F;code&gt; の設定が必要です&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;multilingual_quote&lt;&#x2F;td&gt;&lt;td&gt;原文と翻訳をトグルで切り替え表示できる引用ブロックです。英語の技術ドキュメントを引用する際に原文と日本語訳を並べて見せられます&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;references&lt;&#x2F;td&gt;&lt;td&gt;参考文献をスタイル付きで表示するブロックです。学術的な記事や多くの出典をまとめる場合に適しています&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;remote_text&lt;&#x2F;td&gt;&lt;td&gt;外部URLやローカルファイルの内容を記事内にインラインで埋め込みます。GitHubにあるコンフィグファイルをそのまま表示するような使い方ができます&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;spoiler&lt;&#x2F;td&gt;&lt;td&gt;クリックするまで内容が隠されるテキストブロックです。ネタバレを隠したりクイズの答えを伏せるのに使えます&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;toc&lt;&#x2F;td&gt;&lt;td&gt;記事内に &lt;code&gt;&amp;lt;!-- toc --&amp;gt;&lt;&#x2F;code&gt; マーカーを挿入するショートコードです。マーカーを直接書くのと同等の動作です&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;wide_container&lt;&#x2F;td&gt;&lt;td&gt;記事の本文幅を超えて、ページ全幅にコンテンツを表示します。大きな表やワイドな画像を見切れずに表示したい場合に使えます&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;youtube（自作）&lt;&#x2F;td&gt;&lt;td&gt;YouTube動画を埋め込み表示します&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;以下、このブログで使用しているショートコードから、
よく使うものに絞ってサンプルを載せておきます。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;admonition&quot;&gt;admonition&lt;&#x2F;h3&gt;
&lt;p&gt;info、warning、danger、tip、noteなどの
タイプを指定できます。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;markdown&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;{% admonition(type=&amp;quot;warning&amp;quot;, title=&amp;quot;注意&amp;quot;) %}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;ここに警告メッセージを書きます。&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;{% end %}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;!-- textlint-disable --&gt;
&lt;div class=&quot;admonition warning&quot;&gt;
    &lt;div class=&quot;admonition-icon admonition-icon-warning&quot;&gt;&lt;&#x2F;div&gt;
    &lt;div class=&quot;admonition-content&quot;&gt;
        &lt;strong class=&quot;admonition-title&quot;&gt;注意&lt;&#x2F;strong&gt;
        &lt;p&gt;ここに警告メッセージを書きます。&lt;&#x2F;p&gt;

    &lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;!-- textlint-enable --&gt;
&lt;h3 id=&quot;aside&quot;&gt;aside&lt;&#x2F;h3&gt;
&lt;p&gt;admonitionより控えめな見た目で、
ちょっとした注釈を添えるのに向いています。
PCなどの表示では記事の左右に表示され、
スマートフォンなどでは記事と並んで
表示されます。
&lt;code&gt;position&lt;&#x2F;code&gt; パラメータで配置を調整できます。&lt;&#x2F;p&gt;
&lt;!-- textlint-disable --&gt;
&lt;aside data-position=&quot;right&quot;&gt;
    &lt;p&gt;右側にも表示できます。&lt;&#x2F;p&gt;

&lt;&#x2F;aside&gt;
&lt;!-- textlint-enable --&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;markdown&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;{% aside(position=&amp;quot;right&amp;quot;) %}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;補足情報をここに書きます。&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;{% end %}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;multilingual_quote&quot;&gt;multilingual_quote&lt;&#x2F;h3&gt;
&lt;p&gt;原文と翻訳をトグルで切り替え表示できます。
英語の技術ドキュメントを引用する際に、
原文と日本語訳を並べて見せられます。
&lt;code&gt;author&lt;&#x2F;code&gt; パラメータで出典も表示できます。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;markdown&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;{{ multilingual_quote(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;  translated=&amp;quot;考える、ゆえに我あり。&amp;quot;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;  original=&amp;quot;Cogito, ergo sum.&amp;quot;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;  author=&amp;quot;René Descartes&amp;quot;) }}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;!-- textlint-disable --&gt;
&lt;div class=&quot;quote-container&quot;&gt;
    &lt;input type=&quot;checkbox&quot; id=&quot;toggle-81018&quot; class=&quot;quote-toggle&quot;&gt;
    &lt;div class=&quot;quote&quot;&gt;
        &lt;div class=&quot;translated&quot;&gt;
            &lt;blockquote&gt;
                &lt;p&gt;“考える、ゆえに我あり。”&lt;&#x2F;p&gt;
                &lt;p&gt;— René Descartes &lt;label for=&quot;toggle-81018&quot; class=&quot;quote-label quote-label-original&quot;&gt;
                    (Show original quote)
                &lt;&#x2F;label&gt;&lt;&#x2F;p&gt;
            &lt;&#x2F;blockquote&gt;
        &lt;&#x2F;div&gt;
        &lt;div class=&quot;original&quot;&gt;
            &lt;blockquote&gt;
                &lt;p&gt;“Cogito, ergo sum.”&lt;&#x2F;p&gt;
                &lt;p&gt;— René Descartes &lt;label for=&quot;toggle-81018&quot; class=&quot;quote-label quote-label-translate&quot;&gt;
                    (Show translation)
                &lt;&#x2F;label&gt;&lt;&#x2F;p&gt;
            &lt;&#x2F;blockquote&gt;
        &lt;&#x2F;div&gt;
    &lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;!-- textlint-enable --&gt;
&lt;h3 id=&quot;references&quot;&gt;references&lt;&#x2F;h3&gt;
&lt;p&gt;参考文献をスタイル付きで表示するブロックです。
パラメータはなく、内部にMarkdownを記述できます。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;markdown&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;{% references() %}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-list z-begin z-markdown&quot;&gt;-&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt; WEBサイト. 「&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-link z-title z-string z-other z-link z-title z-markdown&quot;&gt;[記事名]&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-markup z-underline z-link&quot;&gt;https:&#x2F;&#x2F;example.com&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt;」.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-list z-begin z-markdown&quot;&gt;-&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt; 著者(2026). 『書名』.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;  {% end %}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;!-- textlint-disable --&gt;
&lt;div class=&quot;references&quot;&gt;
    &lt;ul&gt;
&lt;li&gt;Example Site. 「&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;example.com&#x2F;article&quot;&gt;Zolaで技術ブログを作る&lt;&#x2F;a&gt;」&lt;&#x2F;li&gt;
&lt;li&gt;結城浩. (2020). 『&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;example.com&#x2F;book&quot;&gt;数学ガール&lt;&#x2F;a&gt;』&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;

&lt;&#x2F;div&gt;
&lt;!-- textlint-enable --&gt;
&lt;h3 id=&quot;spoiler&quot;&gt;spoiler&lt;&#x2F;h3&gt;
&lt;p&gt;クリックするまで内容がぼかされて隠れます。
JavaScriptを使わず、
CSSとチェックボックスで実装されています。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;markdown&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;犯人は、{{ spoiler(text=&amp;quot;執事でした。&amp;quot;) }}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;!-- textlint-disable --&gt;
&lt;p&gt;犯人は、


&lt;label class=&quot;spoiler-container&quot;&gt;
    &lt;input type=&quot;checkbox&quot; id=&quot;spoiler-25645&quot; class=&quot;spoiler-toggle&quot; role=&quot;button&quot; aria-pressed=&quot;false&quot; &#x2F;&gt;
    &lt;span class=&quot;spoiler-content&quot; title=&quot;reveal spoiler&quot; tabindex=&quot;0&quot;&gt;
        &lt;span class=&quot;spoiler-hidden&quot;&gt;執事でした。&lt;&#x2F;p&gt;
&lt;&#x2F;span&gt;
    &lt;&#x2F;span&gt;
&lt;&#x2F;label&gt;
&lt;&#x2F;p&gt;
&lt;!-- textlint-enable --&gt;
&lt;h2 id=&quot;テンプレート&quot;&gt;テンプレート&lt;&#x2F;h2&gt;
&lt;p&gt;tabiでは記事に対して3種類のtemplateが
提供されています。
いずれもセクションの &lt;code&gt;_index.md&lt;&#x2F;code&gt; で有効にします。&lt;&#x2F;p&gt;
&lt;dl&gt;
&lt;dt&gt;section - 通常のテンプレート&lt;&#x2F;dt&gt;
&lt;dd&gt;通常の記事向けのテンプレートです。&lt;&#x2F;dd&gt;
&lt;dt&gt;series — 連載記事テンプレート&lt;&#x2F;dt&gt;
&lt;dd&gt;複数回にわたる連載記事を番号付きインデックスで管理できるテンプレートです。&lt;&#x2F;dd&gt;
&lt;dd&gt;複数回にわたる技術解説記事に向いています。&lt;&#x2F;dd&gt;
&lt;dt&gt;cards — カードグリッドテンプレート&lt;&#x2F;dt&gt;
&lt;dd&gt;フィルタ可能なカードグリッドのレイアウトです。&lt;&#x2F;dd&gt;
&lt;dd&gt;ポートフォリオやプロジェクト一覧を見せるのに適しています。&lt;&#x2F;dd&gt;
&lt;dd&gt;タグによるフィルタリングも可能です。&lt;&#x2F;dd&gt;
&lt;&#x2F;dl&gt;
&lt;h2 id=&quot;サイト設定&quot;&gt;サイト設定&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;code&gt;config.toml&lt;&#x2F;code&gt; の &lt;code&gt;[extra]&lt;&#x2F;code&gt; セクションで
設定できるオプションです。
以下の説明は、筆者が気になったものだけを
取り上げており網羅的ではありません。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;skin_—_カラースキーム&quot;&gt;skin — カラースキーム&lt;&#x2F;h3&gt;
&lt;p&gt;tabiには12種類のカラースキームが用意されています。
sakura、lavender、mint、teal、evangelionなど、
テーマカラーを一行で切り替えられます。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;toml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;extra&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;skin&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;sakura&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;このブログでは &lt;code&gt;custom.css&lt;&#x2F;code&gt; で
独自にカラーを指定しているため使っていません。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;browser_theme_color_—_モバイルブラウザのテーマカラー&quot;&gt;browser_theme_color — モバイルブラウザのテーマカラー&lt;&#x2F;h3&gt;
&lt;p&gt;モバイルブラウザのアドレスバーの色を指定できます。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;toml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;extra&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;browser_theme_color&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;#087e96&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;compact_tags_—_コンパクトなタグクラウド&quot;&gt;compact_tags — コンパクトなタグクラウド&lt;&#x2F;h3&gt;
&lt;p&gt;タグ一覧をコンパクトな上付き数字スタイルで表示します。
タグ数が多いブログで一覧性を高められます。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;toml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;extra&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;compact_tags&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language z-boolean&quot;&gt; true&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;feed_icon_—_RSSアイコン&quot;&gt;feed_icon — RSSアイコン&lt;&#x2F;h3&gt;
&lt;p&gt;フッターにRSSフィードのアイコンを表示します。
当ブログではsocialsを使ってRSSを
表示しているため使用していません。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;toml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;extra&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;feed_icon&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language z-boolean&quot;&gt; true&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;full_content_in_feed_—_フィード全文配信&quot;&gt;full_content_in_feed — フィード全文配信&lt;&#x2F;h3&gt;
&lt;p&gt;Atomフィードに記事の全文を含めます。
当ブログでは既にこの設定を有効にしています。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;toml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;extra&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;full_content_in_feed&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language z-boolean&quot;&gt; true&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;webmentions_—_IndieWeb_Webmentions&quot;&gt;webmentions — IndieWeb Webmentions&lt;&#x2F;h3&gt;
&lt;p&gt;Webmentionによるインタラクションを表示できます。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;toml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;extra.webmentions&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;enable&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language z-boolean&quot;&gt; true&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;domain&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;www.example.com&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;KaTeX_—_数式レンダリング&quot;&gt;KaTeX — 数式レンダリング&lt;&#x2F;h3&gt;
&lt;p&gt;LaTeX形式の数式をレンダリングできます。
数学や統計を扱う記事で使えます。&lt;&#x2F;p&gt;
&lt;p&gt;記事のFrontmatterで有効化します。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;toml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;extra&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;katex&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language z-boolean&quot;&gt; true&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;記事本文では以下のように記述します。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;markdown&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;インライン数式: $E = mc^2$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;ブロック数式: $$\sum_{i=1}^{n} x_i$$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;未使用のFrontmatterオプション&quot;&gt;未使用のFrontmatterオプション&lt;&#x2F;h2&gt;
&lt;p&gt;記事ごとに &lt;code&gt;[extra]&lt;&#x2F;code&gt; セクションで
個別にオーバーライドできる設定です。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;tldr&quot;&gt;tldr&lt;&#x2F;h3&gt;
&lt;p&gt;これまでセクションを設けて記載していましたが、
Frontmatterで設定できることがわかりました。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;updated_—_最終更新日&quot;&gt;updated — 最終更新日&lt;&#x2F;h3&gt;
&lt;p&gt;記事の最終更新日を &lt;code&gt;date&lt;&#x2F;code&gt; とは別に表示します。
内容を更新した記事に設定すると、
読者に最新性を伝えられます。
&lt;code&gt;[extra]&lt;&#x2F;code&gt; ではなくトップレベルの
Frontmatterフィールドです。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;toml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;+++&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;title&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;記事タイトル&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;date&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; 2026-02-01&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;updated&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; 2026-02-20&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;+++&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;show_reading_time_—_読了時間の個別制御&quot;&gt;show_reading_time — 読了時間の個別制御&lt;&#x2F;h3&gt;
&lt;p&gt;グローバルでは有効にしていますが、
短い記事では非表示にできます。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;toml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;extra&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;show_reading_time&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language z-boolean&quot;&gt; false&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;giscus_—_コメントの個別制御&quot;&gt;giscus — コメントの個別制御&lt;&#x2F;h3&gt;
&lt;p&gt;グローバルでは全記事で有効ですが、
特定の記事でコメントを無効にできます。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;toml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;extra&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;giscus&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language z-boolean&quot;&gt; false&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;toc_—_目次の個別制御&quot;&gt;toc — 目次の個別制御&lt;&#x2F;h3&gt;
&lt;p&gt;グローバル設定とは別に、
記事ごとに目次の表示を制御できます。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;toml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;extra&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;toc&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language z-boolean&quot;&gt; true&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;このブログでは &lt;code&gt;&amp;lt;!-- toc --&amp;gt;&lt;&#x2F;code&gt; マーカーを
&lt;code&gt;details&lt;&#x2F;code&gt;要素に入れて、畳めるようにしているため利用していませんが、
そのような要件がなければ
Frontmatterで制御するほうがシンプルです。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;まとめ&quot;&gt;まとめ&lt;&#x2F;h2&gt;
&lt;p&gt;tabiは使い切れないほど多機能なテーマです。
今回改めて棚卸しをしてみると、
これまで使っていなかった機能のなかにも
便利なものが数多く存在しました。&lt;&#x2F;p&gt;
&lt;p&gt;たとえば &lt;code&gt;tldr&lt;&#x2F;code&gt; はこれまで記事本文に
セクションを設けて書いていましたが、
Frontmatterに設定するだけで済むと知り、
今後は積極的に活用していきます。
&lt;code&gt;updated&lt;&#x2F;code&gt; による最終更新日の表示なども、
知っていれば必要な場面ですぐに使える
実用的なオプションです。&lt;&#x2F;p&gt;
&lt;p&gt;テンプレートについても、
これまでは通常の &lt;code&gt;section&lt;&#x2F;code&gt; テンプレートしか
使っていませんでしたが、
&lt;code&gt;series&lt;&#x2F;code&gt; テンプレートは複数回にわたる
連載記事をまとめるのに向いており、
技術解説のシリーズ記事などで
活用していきたいと考えています。
&lt;code&gt;cards&lt;&#x2F;code&gt; テンプレートも、
ポートフォリオやプロジェクト一覧のような
通常のブログ記事とは異なるタイプの
コンテンツを見せる場面で使えそうです。&lt;&#x2F;p&gt;
&lt;p&gt;使える機能を把握しておくだけでも、
記事の表現の幅が広がります。
テーマの機能を活かしきれていないと
感じている方は、一度公式ドキュメントを
眺めてみることをおすすめします。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;References&quot;&gt;References&lt;&#x2F;h2&gt;
&lt;!-- textlint-disable --&gt;
&lt;div class=&quot;references&quot;&gt;
    &lt;ul&gt;
&lt;li&gt;tabi. &quot;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;welpo.github.io&#x2F;tabi&#x2F;&quot;&gt;tabi documentation&lt;&#x2F;a&gt;&quot;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;

&lt;&#x2F;div&gt;
&lt;!-- textlint-enable --&gt;
</content>
        <summary type="html">Zolaの高機能テーマ「tabi」には、
普段使っていない便利な機能が数多く眠っています。
ショートコード、テンプレート、Frontmatterオプションまで、
見落としがちな機能をまとめて紹介します。
</summary>
        </entry><entry xml:lang="en">
        <title>もしかしてだけど、あれって日本最古のアスキーアートだったんじゃないの？</title>
        <published>2026-02-21T00:00:00+00:00</published>
        <updated>2026-02-21T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2026/02/img2char-ascii-art-1986/" type="text/html"/>
        <id>https://codedchords.dev/blog/2026/02/img2char-ascii-art-1986/</id>
        
            <content type="html">&lt;h2 id=&quot;はじめに&quot;&gt;はじめに&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;img
  src=&quot;https:&amp;#x2F;&amp;#x2F;codedchords.dev&amp;#x2F;blog&amp;#x2F;2026&amp;#x2F;02&amp;#x2F;img2char-ascii-art-1986&amp;#x2F;cover.webp?h=23adb599ec98a887ae4f&quot;
  alt=&quot;img2charによる変換例&quot; width=&quot;800&quot; height=&quot;485&quot; loading=&quot;lazy&quot;
&#x2F;&gt;
&lt;em&gt;左の画像はMidjourneyで生成したものです&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;1986年、パソコン通信は黎明期でASCIInetがまだ実験運用の時代でした。その頃の私はグラフィック（おそらくモノクロの有名歌手の画像）を自作プログラムでASCII文字の絵にして、あるパソコン通信のBBS（電子掲示板）に投稿しました。&lt;&#x2F;p&gt;
&lt;p&gt;あれから約40年。当時のアルゴリズムをGoで再実装し、CLIツール &lt;code&gt;img2char&lt;&#x2F;code&gt; として公開しました。&lt;&#x2F;p&gt;
&lt;iframe class=&quot;hatenablogcard&quot; src=&quot;https:&#x2F;&#x2F;hatenablog-parts.com&#x2F;embed?url=https:&amp;#x2F;&amp;#x2F;github.com&amp;#x2F;yostos&amp;#x2F;img2char&quot; width=&quot;100%&quot; height=&quot;155&quot; frameborder=&quot;0&quot; scrolling=&quot;no&quot; loading=&quot;lazy&quot;&gt;&lt;&#x2F;iframe&gt;
&lt;p&gt;この記事では、当時の背景と &lt;code&gt;img2char&lt;&#x2F;code&gt; のアルゴリズムを紹介します。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;1986年のパソコンとBBS&quot;&gt;1986年のパソコンとBBS&lt;&#x2F;h2&gt;
&lt;p&gt;1986年はPC-VAN（1986年4月実験開始）やNIFTY-Serve（1987年4月開始）が立ち上がり始めた、日本のパソコン通信黎明期です。アスキーネット（ASCII-NET）は前年の1985年5月に実験サービスを開始しており、草の根BBSも各地で産声を上げていました。通信速度は300bpsから1200bps。BBSに書き込めるのはテキストだけの時代でした。グラフィックスを書き込むなんてとんでもない時代でした&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-1-1&quot;&gt;&lt;a href=&quot;#fn-1&quot;&gt;1&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;。&lt;&#x2F;p&gt;
&lt;p&gt;当時のパソコンのグラフィック事情も触れておきます。1986年時点では、画像をファイルとして保存・交換する汎用フォーマットはまだ普及していませんでした。グラフィックを描くといえば、BASICのLINE文やPAINT文を使ってプログラムとして記述するのが主流です。私自身、PAINT文を使わずに画像の上端から下端まで（縦200ドットしかない画面です）をLINE文だけで1ラインずつ塗りつぶし、モノクロ画像を描くことに当時凝っていました。グラフィックは「描く」ものであって「ファイルで送る」ものではなかったのです。&lt;&#x2F;p&gt;
&lt;p&gt;しかもBASICは機種ごとに方言が異なり、あるマシンで書いたプログラムが別のマシンでそのまま動くことはまずありません。グラフィック描画プログラムをBBSで流通させるのも現実的ではありませんでした。&lt;&#x2F;p&gt;
&lt;p&gt;そこで思いついたのが、「ASCII文字絵にすれば遅いパソコン通信でも送れるんじゃね？」です。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;Sharp_X1_──_骨の髄までハードを極めたマシン&quot;&gt;Sharp X1 ── 骨の髄までハードを極めたマシン&lt;&#x2F;h2&gt;
&lt;p&gt;Sharp X1は1982年に発売された8ビットパソコンです。テレビ事業で培ったシャープの技術が随所に活かされた、ハードウェア設計の塊のようなマシンでした。&lt;&#x2F;p&gt;
&lt;p&gt;当時のZ80 CPUはメモリ空間が64KBしかなく、NECのPC-8801などではこの空間にメインRAMとグラフィックVRAM（GVRAM）を重ねて配置し、バンク切り替えでアクセスしていました。一方X1は、Z80のI&#x2F;O命令が実行時にアドレスバスの上位8ビット（A8〜A15）にもレジスタの値を出力するという、公式マニュアルには記載されているものの目立たない仕様を活用しました。I&#x2F;O空間を実質64KBに広げ、そこにGVRAMを配置したのです。メモリ空間64KBは丸ごとRAMとして使え、GVRAMへはI&#x2F;O命令で直接アクセスできます。&lt;&#x2F;p&gt;
&lt;p&gt;この設計のおかげで、BASICからでもグラフィックVRAM上の画像データを読み出すことができました。グラフィックVRAM上の画像を8x8ドット単位で読み取り、キャラクタROMの各文字パターンと比較する。一致度が最も高い文字を選ぶ。このアルゴリズムをBASICで実装しました&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-2-1&quot;&gt;&lt;a href=&quot;#fn-2&quot;&gt;2&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;アルゴリズムの現代版_──_img2char&quot;&gt;アルゴリズムの現代版 ── img2char&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;code&gt;img2char&lt;&#x2F;code&gt; は、あの当時のアルゴリズムをGoで忠実に再現したCLIツールです。処理は3段階で構成されています。&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;フォントパターンの準備&lt;&#x2F;strong&gt; ── 95個のASCII印字可能文字の8x8ビットマップを用意する&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;画像のブロック分割&lt;&#x2F;strong&gt; ── 入力画像を8x8ピクセルのブロックに分割する&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;パターンマッチング&lt;&#x2F;strong&gt; ── 各ブロックとフォントパターンのハミング距離を計算し、最も近い文字を選ぶ&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;h3 id=&quot;フォントテーブルの構築&quot;&gt;フォントテーブルの構築&lt;&#x2F;h3&gt;
&lt;p&gt;95個の印字可能ASCII文字（スペース &lt;code&gt;0x20&lt;&#x2F;code&gt; からチルダ &lt;code&gt;0x7E&lt;&#x2F;code&gt; まで）について、それぞれ8x8ドットのビットマップパターンを持っています。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;go&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;&#x2F;&#x2F; font8x8Basic contains 8x8 bitmap patterns for 95 printable ASCII characters (0x20–0x7E).&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;var&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; font8x8Basic&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;95&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;][&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;8&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;byte&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;    &#x2F;&#x2F; 0x20 &amp;#39; &amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    {&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;0x&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;00&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; 0x&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;00&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; 0x&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;00&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; 0x&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;00&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; 0x&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;00&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; 0x&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;00&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; 0x&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;00&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; 0x&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;00&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;},&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;    &#x2F;&#x2F; 0x21 &amp;#39;!&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    {&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;0x&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;18&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; 0x&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;3C&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; 0x&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;3C&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; 0x&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;18&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; 0x&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;18&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; 0x&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;00&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; 0x&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;18&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; 0x&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;00&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;},&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;    &#x2F;&#x2F; 0x22 &amp;#39;&amp;quot;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    {&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;0x&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;36&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; 0x&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;36&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; 0x&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;00&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; 0x&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;00&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; 0x&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;00&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; 0x&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;00&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; 0x&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;00&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; 0x&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;00&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;},&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;    &#x2F;&#x2F; ... 95文字分のパターンが続く&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;    &#x2F;&#x2F; 0x41 &amp;#39;A&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    {&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;0x&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;0C&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; 0x&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;1E&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; 0x&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;33&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; 0x&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;33&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; 0x&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;3F&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; 0x&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;33&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; 0x&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;33&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; 0x&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;00&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;},&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;    &#x2F;&#x2F; 0x7E &amp;#39;~&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    {&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;0x&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;6E&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; 0x&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;3B&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; 0x&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;00&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; 0x&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;00&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; 0x&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;00&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; 0x&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;00&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; 0x&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;00&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; 0x&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;00&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;},&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;各バイトが8x8ビットマップの1行に対応し、LSB（最下位ビット）が左端のピクセルです。たとえば &lt;code&gt;A&lt;&#x2F;code&gt; のパターンを展開すると、以下のようになります。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;(2進数はLSB=左端ピクセルから表記)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;0x0C = 00110000 → ..##....&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;0x1E = 01111000 → .####...&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;0x33 = 11001100 → ##..##..&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;0x33 = 11001100 → ##..##..&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;0x3F = 11111100 → ######..&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;0x33 = 11001100 → ##..##..&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;0x33 = 11001100 → ##..##..&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;0x00 = 00000000 → ........&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;8バイトで1文字の形が表現されています。高速な比較のため &lt;code&gt;uint64&lt;&#x2F;code&gt; にパックします。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;go&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;func&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; packFont&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt;pattern&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;8&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;byte&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt; uint64&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;    var&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; v&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt; uint64&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;    for&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; i&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; :=&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 0&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; i&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; &amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 8&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; i&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;++&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;        v&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; |=&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt; uint64&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;pattern&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;i&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;])&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; &amp;lt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; (&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;i&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; *&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 8&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;    return&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; v&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;X1に搭載されていたHu-BASICの整数型は16ビット（2バイト）なので、当時は8バイトのパターンを2バイトずつ4回のXORループで比較していました。現代のGoでは8バイトを1つの64ビット整数に詰め込むことで、後述のXOR演算が一発で実行できます。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;8x8ブロックとフォントパターンの照合&quot;&gt;8x8ブロックとフォントパターンの照合&lt;&#x2F;h3&gt;
&lt;p&gt;ここが核心部分です。画像から切り出した8x8ブロックを、95文字すべてのフォントパターンと比較し、最も「形が近い」文字を見つけます。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;go&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;func&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; matchChar&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt;block&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;8&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;byte&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt; fontTable&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;95&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;uint64&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt; byte&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    blockVal&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; :=&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; packBlock&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;block&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    bestDist&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; :=&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 65&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt; &#x2F;&#x2F; max possible is 64&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    bestIdx&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; :=&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;    for&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; i&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; :=&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 0&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; i&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; &amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 95&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; i&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;++&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;        dist&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; :=&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; bits&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;OnesCount64&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;blockVal&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; ^&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; fontTable&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;i&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;])&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;        if&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; dist&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; &amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; bestDist&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;            bestDist&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; dist&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;            bestIdx&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; i&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;        }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-storage z-type&quot;&gt;    return byte&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;0x&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;20&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; +&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; bestIdx&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;code&gt;blockVal ^ fontTable[i]&lt;&#x2F;code&gt; のXOR演算で、ブロックとフォントパターンのビットが異なる位置を検出します。&lt;code&gt;bits.OnesCount64&lt;&#x2F;code&gt; でその異なるビット数（ハミング距離）を数えます。64ビット中の不一致ビット数が最小の文字を選ぶ、シンプルかつ強力な方式です。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;使い方&quot;&gt;使い方&lt;&#x2F;h3&gt;
&lt;p&gt;入力画像は640x200または320x200ピクセルの二値化済みPNGである必要があります。前処理用のシェルスクリプトが付属しています。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# 前処理（ImageMagickでリサイズ＋二値化）&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;.&#x2F;convert.sh&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; input.jpg&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 640 200&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# ASCII文字に変換&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;img2char&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; input_640x200.png&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;640x200の画像は80x25文字、320x200なら40x25文字に変換されます。当時は320x200モードの40x25文字でやっていました。&lt;&#x2F;p&gt;
&lt;p&gt;今回、同じロジックで似たような画像を変換してみましたが、なかなかいけています（冒頭の画像を参照）。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;もしかして......日本最古のASCII_Artなんじゃないの？&quot;&gt;もしかして......日本最古のASCII Artなんじゃないの？&lt;&#x2F;h2&gt;
&lt;p&gt;当時の変換結果をパソコン通信のBBSに投稿したところ、ちょっとした話題になりました。テキストしか表示できない端末に、文字だけで画像が浮かび上がるのですから、当時としては驚きだったようです。40x25文字分の解像度しかありませんが、元の画像の輪郭や特徴が文字の組み合わせで再現される様子は、見た人を楽しませるものでした。&lt;&#x2F;p&gt;
&lt;p&gt;ここで少し大胆なことを言わせてください。&lt;&#x2F;p&gt;
&lt;p&gt;文字で画像を表現する試み自体は古く、1898年のタイプライターアートにまで遡ります。コンピューターによる自動変換も、1967年にベル研究所のケネス・ノウルトンがIBM 7094で実現しています。ただしそれは巨大なメインフレームでの話です。&lt;&#x2F;p&gt;
&lt;p&gt;日本に目を向けると、記録に残る最古の「アスキーアート」は1986年6月20日にアスキーネット上で若林泰志が投稿した顔文字 &lt;code&gt;(^_^)&lt;&#x2F;code&gt; とされています。2ちゃんねるでAAが花開くのは1999年以降。1986年当時、手作業でAA（アスキーアート）を描く文化はまだ広まっていませんでした。&lt;&#x2F;p&gt;
&lt;p&gt;そんな時代に、8ビットパソコンで画像をASCII文字に変換してBBSに投稿していたわけです。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;もしかして、もしかしてだけど、これって日本最古のアスキーアートなんじゃないの？&lt;&#x2F;strong&gt;（どぶろっく風）&lt;&#x2F;p&gt;
&lt;p&gt;......まあ、証拠は当時のBBSのログとともに電子の海に消えてしまいましたが。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;まとめ&quot;&gt;まとめ&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;code&gt;img2char&lt;&#x2F;code&gt; は、1986年のSharp X1で生まれたアイデアを現代のGoで再実装したツールです。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;当時のパソコン通信の制約（テキストのみ）が生んだ発想&lt;&#x2F;li&gt;
&lt;li&gt;PCGという強力なハードウェアをあえて使わず、ASCII文字だけで勝負した選択&lt;&#x2F;li&gt;
&lt;li&gt;8x8ドットブロックとフォントパターンのハミング距離による照合という、シンプルだが効果的なアルゴリズム&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;40年前のBASICプログラムが64ビット整数のXOR演算に姿を変えても、やっていることは同じです。画像の形を文字の形で近似する。それだけのことが、なぜか人を惹きつけます。&lt;&#x2F;p&gt;
&lt;p&gt;興味を持っていただけたら、ぜひ試してみてください。&lt;&#x2F;p&gt;
&lt;iframe class=&quot;hatenablogcard&quot; src=&quot;https:&#x2F;&#x2F;hatenablog-parts.com&#x2F;embed?url=https:&amp;#x2F;&amp;#x2F;github.com&amp;#x2F;yostos&amp;#x2F;img2char&quot; width=&quot;100%&quot; height=&quot;155&quot; frameborder=&quot;0&quot; scrolling=&quot;no&quot; loading=&quot;lazy&quot;&gt;&lt;&#x2F;iframe&gt;
&lt;h2 id=&quot;参考&quot;&gt;参考&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;ja.wikipedia.org&#x2F;wiki&#x2F;%E3%82%A2%E3%82%B9%E3%82%AD%E3%83%BC%E3%82%A2%E3%83%BC%E3%83%88&quot;&gt;アスキーアート - Wikipedia&lt;&#x2F;a&gt; -- 日本におけるアスキーアートの歴史、顔文字の起源&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;ASCII_art&quot;&gt;ASCII art - Wikipedia (English)&lt;&#x2F;a&gt; -- タイプライターアート（1898年）からの世界的な歴史&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.asciiart.eu&#x2F;history-of-ascii-art&quot;&gt;The history of ASCII Art - ASCII Art Archive&lt;&#x2F;a&gt; -- ベル研のノウルトン（1967年）による自動変換の歴史&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;ja.wikipedia.org&#x2F;wiki&#x2F;X1_%28%E3%82%B3%E3%83%B3%E3%83%94%E3%83%A5%E3%83%BC%E3%82%BF%29&quot;&gt;X1 (コンピュータ) - Wikipedia&lt;&#x2F;a&gt; -- Sharp X1のハードウェア仕様&lt;&#x2F;li&gt;
&lt;li&gt;Z80の16ビットI&#x2F;Oアドレスについての考察（大石氏）-- Z80のI&#x2F;O命令が16ビットアドレスを出力する仕様の解説（サイト閉鎖）&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;electrelic.com&#x2F;electrelic&#x2F;node&#x2F;639&quot;&gt;パーソナルなコンピュータのメモリ事情（第3回：8ビット中期）- Electrelic&lt;&#x2F;a&gt; -- X1とPC-8801のGVRAM配置方式の比較&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;www.kogures.com&#x2F;hitoshi&#x2F;history&#x2F;pc-tushin&#x2F;index.html&quot;&gt;パソコン通信の歴史 - 木暮仁&lt;&#x2F;a&gt; -- PC-VAN、NIFTY-Serve、草の根BBSの歴史&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;!-- textlint-enable --&gt;
&lt;section class=&quot;footnotes&quot;&gt;
&lt;ol class=&quot;footnotes-list&quot;&gt;
&lt;li id=&quot;fn-1&quot;&gt;
&lt;p&gt;そもそも画像をファイルに書き出すフォーマットさえ標準的なものはなかった。 &lt;a href=&quot;#fr-1-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li id=&quot;fn-2&quot;&gt;
&lt;p&gt;X1にはPCG（Programmable Character Generator）が搭載されており、文字のフォントパターンを自由に書き換えられました。任意のドットパターンを「文字」として表示でき、グラフィックスに近い表現が可能でした。しかしBBSに投稿するならPCGは使えません。相手の画面にPCGのデータは存在せず、表示できるのは標準のASCII文字だけだからです。 &lt;a href=&quot;#fr-2-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;&#x2F;section&gt;
</content>
        <summary type="html">1986年、8ビットパソコンSharp X1で画像をASCII文字に自動変換し、
パソコン通信のBBSに投稿していました。当時のアルゴリズムを
GoでCLIツール img2char として再実装した経緯と技術を紹介します。
</summary>
        </entry><entry xml:lang="en">
        <title>Cloudflare無料プランだけで個人サイトのセキュリティが完結した話</title>
        <published>2026-02-20T00:00:00+00:00</published>
        <updated>2026-02-20T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2026/02/cloudflare-benefits/" type="text/html"/>
        <id>https://codedchords.dev/blog/2026/02/cloudflare-benefits/</id>
        
            <content type="html">&lt;!-- textlint-disable --&gt;
&lt;img
  src=&quot;https:&amp;#x2F;&amp;#x2F;codedchords.dev&amp;#x2F;blog&amp;#x2F;2026&amp;#x2F;02&amp;#x2F;cloudflare-benefits&amp;#x2F;cover.webp?h=a800061cf7b938db4dbe&quot;
  alt=&quot;Cover&quot; width=&quot;1792&quot; height=&quot;1024&quot; loading=&quot;lazy&quot;
&#x2F;&gt;&lt;h2 id=&quot;TL;DR&quot;&gt;TL;DR&lt;&#x2F;h2&gt;
&lt;p&gt;Cloudflareのアドバンテージは、次の3点です。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;無料プランだけでWAF・ボット対策まで揃う、セキュリティの充実度&lt;&#x2F;li&gt;
&lt;li&gt;DNS統合だからこそ、煩雑でリスクの高い設定をワンクリックで実現&lt;&#x2F;li&gt;
&lt;li&gt;AIクローラー対策やページ先読みなど、最新トレンドへの即応&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;つい3日前に&lt;a href=&quot;https:&#x2F;&#x2F;codedchords.dev&#x2F;blog&#x2F;2026&#x2F;02&#x2F;migration-to-cloudflare&#x2F;&quot;&gt;Cloudflareへ移転した&lt;&#x2F;a&gt;ばかりです。構成はシンプルで、Cloudflareでドメインを取得し、GitHubリポジトリと連携して静的コンテンツをCloudflare Pages&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-2-1&quot;&gt;&lt;a href=&quot;#fn-2&quot;&gt;1&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;へデプロイしています。この構成だけでも思いの外多くの恩恵が得られたので、まとめておきます。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;Cloudflareでの設定&quot;&gt;Cloudflareでの設定&lt;&#x2F;h2&gt;
&lt;p&gt;Cloudflareのダッシュボードで有効にした機能を、カテゴリごとに紹介します。いずれも無料プランで利用でき、ほとんどがトグルひとつで有効にできるものです。なお、本記事の機能名やβ表記は2026年2月時点のCloudflare管理画面のUIに基づいています。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;Edge_Certificates&quot;&gt;Edge Certificates&lt;&#x2F;h3&gt;
&lt;p&gt;Cloudflareが発行・管理するSSL&#x2F;TLS証明書と、HTTPS通信に関する設定です。&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;項目&lt;&#x2F;th&gt;&lt;th&gt;説明&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;Always Use HTTPS&lt;&#x2F;td&gt;&lt;td&gt;HTTP でアクセスが来た場合に自動的に HTTPS へ301リダイレクトしてくれるので、暗号化されていない通信を防げる。&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;HSTS&lt;&#x2F;td&gt;&lt;td&gt;&lt;code&gt;.dev&lt;&#x2F;code&gt; ドメイン&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-1-1&quot;&gt;&lt;a href=&quot;#fn-1&quot;&gt;2&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;を使用しているので私の場合あまり恩恵がないが、ブラウザレベルでHTTPSが強制できる。&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Minimum TLS Version&lt;&#x2F;td&gt;&lt;td&gt;サイトに接続する際に許可するTLSプロトコルの最低バージョンの指定。TLS 1.0 と 1.1 は既知の脆弱性があるので、私はTLS1.2にしている。&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Opportunistic Encryption&lt;&#x2F;td&gt;&lt;td&gt;HTTPでアクセスしてきたブラウザに対して「暗号化接続も利用可能ですよ」と通知する仕組み。&lt;code&gt;.dev&lt;&#x2F;code&gt; の場合、HTTPアクセスが発生しないので実質的に意味がない。&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;TLS 1.3&lt;&#x2F;td&gt;&lt;td&gt;Minimum TLS Version を 1.2 に設定し、この TLS 1.3 をオンにしておけば、「最低 1.2、対応していれば 1.3 を使う」という構成になる。&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Automatic HTTPS Rewrites&lt;&#x2F;td&gt;&lt;td&gt;&lt;code&gt;http:&#x2F;&#x2F;&lt;&#x2F;code&gt; をCloudflare が自動的に &lt;code&gt;https:&#x2F;&#x2F;&lt;&#x2F;code&gt; に書き換えて「混在コンテンツ（mixed content）」の問題を防いでくれる。&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Certificate Transparency Monitoring&lt;&#x2F;td&gt;&lt;td&gt;自分が意図していない証明書が第三者によって発行された場合（ドメインの不正利用や乗っ取りの兆候）通知してくれる&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;h3 id=&quot;Security&quot;&gt;Security&lt;&#x2F;h3&gt;
&lt;p&gt;ボット対策、DDoS防御、WAFなど、サイトを外部の脅威から守るための設定です。&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;項目&lt;&#x2F;th&gt;&lt;th&gt;説明&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;AI Labyrinth&lt;&#x2F;td&gt;&lt;td&gt;まだβ機能だが、robots.txt 等のクロールルールを無視して勝手にサイトをスクレイピングするボットに対して偽コンテンツを読ませて学習データを汚染させるという「ハニーポット」的な機能&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Block AI bots&lt;&#x2F;td&gt;&lt;td&gt;AI学習用クローラーをブロックする機能&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Bot fight mode&lt;&#x2F;td&gt;&lt;td&gt;悪意のあるボット（スパム、クレデンシャルスタッフィング、DDoS等）を検知すると、JavaScriptチャレンジを出して人間かどうかを確認する&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Browser Integrity Check&lt;&#x2F;td&gt;&lt;td&gt;訪問者のHTTPヘッダーを検査して、不正なUser-Agentやスパムボットによく見られる異常なヘッダーパターンを検出し、脅威が見つかった場合はブロックページを表示する。&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Challenge passage&lt;&#x2F;td&gt;&lt;td&gt;チャレンジ（CAPTCHA等）をクリアした訪問者が、再度チャレンジを求められるまでの有効時間&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;HTTP DDoS attack protection&lt;&#x2F;td&gt;&lt;td&gt;HTTPレイヤーのDDoS攻撃を自動検知・緩和する。無料プランでもCloudflare Free Managed Ruleset（基本的なWAFルール）が付属する&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Manage your robots.txt&lt;&#x2F;td&gt;&lt;td&gt;Cloudflare が robots.txt を自動管理するβ機能。Content Signals Policyを選択すると、コンテンツの利用意図を用途別（検索・AI入力・AI学習）に宣言できる&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Network-layer DDoS attack protection&lt;&#x2F;td&gt;&lt;td&gt;DDoS保護&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;h3 id=&quot;DNS&quot;&gt;DNS&lt;&#x2F;h3&gt;
&lt;p&gt;DNS応答の改ざん防止やメールのなりすまし対策など、ドメインの信頼性を高める設定です。&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;項目&lt;&#x2F;th&gt;&lt;th&gt;説明&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;DNSSEC&lt;&#x2F;td&gt;&lt;td&gt;DNSレスポンスに暗号署名を付与して、DNS応答の偽造（DNSキャッシュポイズニング等）を防ぐ&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Email Security&lt;&#x2F;td&gt;&lt;td&gt;有効にしてDMARCの設定。メール送信の予定はないので、SPFは&quot;v=spf1 -all&quot;で設定。DMARCは&quot;v=DMARC1; p=reject&quot;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;h3 id=&quot;Speed&quot;&gt;Speed&lt;&#x2F;h3&gt;
&lt;p&gt;通信プロトコルの最適化やページ先読みなど、サイト表示を高速化するための設定です。&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;項目&lt;&#x2F;th&gt;&lt;th&gt;説明&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;Web analytics using real user measurement (RUM)&lt;&#x2F;td&gt;&lt;td&gt;実際の訪問者のブラウザからパフォーマンスデータ（ページ読み込み時間など）を収集する。Cookieを使わないプライバシー重視の計測方式&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Speed Brain&lt;&#x2F;td&gt;&lt;td&gt;ユーザーがリンクをクリックする前にページを先読みする機能。Speculation Rules API を使い、体感的なページ遷移が高速になる&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;HTTP&#x2F;2&lt;&#x2F;td&gt;&lt;td&gt;HTTP&#x2F;1.1の後継。1つの接続で複数リクエストを並行処理（多重化）でき、ページ読み込みが高速になる&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;HTTP&#x2F;3&lt;&#x2F;td&gt;&lt;td&gt;HTTP&#x2F;2の次世代版。TCPの代わりにQUICプロトコルを使い、接続確立が高速でパケットロス時の劣化も少ない&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;HTTP&#x2F;2 to Origin&lt;&#x2F;td&gt;&lt;td&gt;Cloudflareとオリジンサーバー間の通信にもHTTP&#x2F;2を使う設定&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;0-RTT Connection Resumption&lt;&#x2F;td&gt;&lt;td&gt;TLS 1.3で接続済みのクライアントが再訪問時にハンドシェイクの最初の往復を省略でき、再訪問者の初回リクエストが速くなる&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;h2 id=&quot;以前のプラットフォームとの比較&quot;&gt;以前のプラットフォームとの比較&lt;&#x2F;h2&gt;
&lt;p&gt;昨年までAmazon Amplify、先月までGitHub Pagesで運用していました。
上記で挙げたCloudflareの機能が、それぞれの環境ではどうだったかを比較してみます。特にセキュリティ列の差に注目してください。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;○: 標準&#x2F;無料で利用可能&lt;&#x2F;li&gt;
&lt;li&gt;△: 別途設定や追加費用で対応可能&lt;&#x2F;li&gt;
&lt;li&gt;×: 非対応&lt;&#x2F;li&gt;
&lt;li&gt;−: 該当なし&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;機能&lt;&#x2F;th&gt;&lt;th style=&quot;text-align: center&quot;&gt;Amplify + CloudFront&lt;&#x2F;th&gt;&lt;th style=&quot;text-align: center&quot;&gt;GitHub Pages&lt;&#x2F;th&gt;&lt;th&gt;コメント&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;Always Use HTTPS&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;○&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;○&lt;&#x2F;td&gt;&lt;td&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;HSTS&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;△（手動設定）&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;○&lt;&#x2F;td&gt;&lt;td&gt;AWSだけ手動設定の手間がかかる&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Minimum TLS Version&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;○&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;×&lt;&#x2F;td&gt;&lt;td&gt;GitHub Pagesは古いTLSを拒否できず、セキュリティポリシーを徹底しにくい&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Opportunistic Encryption&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;×&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;×&lt;&#x2F;td&gt;&lt;td&gt;HTTP接続の暗号化への誘導は他のサービスでは提供されていない&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;TLS 1.3&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;○&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;○&lt;&#x2F;td&gt;&lt;td&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Automatic HTTPS Rewrites&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;×&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;×&lt;&#x2F;td&gt;&lt;td&gt;他では混在コンテンツを自分で探して直す必要がある&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Certificate Transparency Monitoring&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;△（ACMの一部）&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;×&lt;&#x2F;td&gt;&lt;td&gt;不正な証明書発行の早期発見に差が出る&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;AI Labyrinth&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;×&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;×&lt;&#x2F;td&gt;&lt;td&gt;ワンクリックでAIスクレイピングに対抗できる機能は他にない&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Block AI bots&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;△（WAFルールで対応）&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;×&lt;&#x2F;td&gt;&lt;td&gt;AWSは自前でルールを書く手間とWAF費用がかかる&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Bot fight mode&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;△（WAF Bot Control有料）&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;×&lt;&#x2F;td&gt;&lt;td&gt;AWSで同等機能を得るにはBot Control（月額$10〜＋リクエスト従量課金）が必要&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Browser Integrity Check&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;△（WAFで部分的）&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;×&lt;&#x2F;td&gt;&lt;td&gt;AWSでは同等ルールの自作が必要で、運用負荷が高い&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Challenge passage&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;△（WAF）&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;×&lt;&#x2F;td&gt;&lt;td&gt;Cloudflareはチャレンジの有効期間まで細かく制御できる&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;HTTP DDoS attack protection&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;△（WAFは有料）&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;×&lt;&#x2F;td&gt;&lt;td&gt;無料でWAFまで付くのはCloudflareの大きな強み&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Manage your robots.txt&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;×&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;×&lt;&#x2F;td&gt;&lt;td&gt;増え続けるAIクローラーへの対応を自動化できる機能は他にない&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Network-layer DDoS attack protection&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;○（Shield Standard）&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;○&lt;&#x2F;td&gt;&lt;td&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;DNSSEC&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;○（Route 53）&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;△（DNS providerに依存）&lt;&#x2F;td&gt;&lt;td&gt;Cloudflareはワンクリック、DNS一体管理なので設定が圧倒的に楽&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Email Security&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;○（Route 53）&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;△（DNS providerに依存）&lt;&#x2F;td&gt;&lt;td&gt;同上。DNS管理とセットなのでSPF&#x2F;DMARCの設定も迷わない&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Web analytics (RUM)&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;△（CloudWatch RUM有料）&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;×&lt;&#x2F;td&gt;&lt;td&gt;Cloudflareは追加費用なしでCookie不要の計測が使える&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Speed Brain&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;×&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;×&lt;&#x2F;td&gt;&lt;td&gt;ページ先読みによる体感速度向上は他のサービスでは提供されていない&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;HTTP&#x2F;2&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;○&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;○&lt;&#x2F;td&gt;&lt;td&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;HTTP&#x2F;3&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;○&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;×&lt;&#x2F;td&gt;&lt;td&gt;GitHub Pagesは2026年2月時点でHTTP&#x2F;3未サポート&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;HTTP&#x2F;2 to Origin&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;○&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;−&lt;&#x2F;td&gt;&lt;td&gt;オリジンサーバーがある構成でのみ意味がある&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;0-RTT&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;×&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;×&lt;&#x2F;td&gt;&lt;td&gt;再訪問時の体感速度に差が出る。他のサービスでは無料で提供されていない&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;h2 id=&quot;AI時代のコンテンツ保護&quot;&gt;AI時代のコンテンツ保護&lt;&#x2F;h2&gt;
&lt;p&gt;Cloudflareの無料プランには、AIクローラーに対応する機能が複数用意されています。これらは独立した機能ですが、組み合わせると多層的な防御になります。&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;機能&lt;&#x2F;th&gt;&lt;th&gt;レイヤー&lt;&#x2F;th&gt;&lt;th&gt;役割&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;Content Signals Policy&lt;&#x2F;td&gt;&lt;td&gt;意思表示&lt;&#x2F;td&gt;&lt;td&gt;robots.txt内でコンテンツの用途別に許可&#x2F;拒否を宣言する。強制力はなく、善意あるクローラーへの「お願い」&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Block AI bots&lt;&#x2F;td&gt;&lt;td&gt;技術的ブロック&lt;&#x2F;td&gt;&lt;td&gt;Cloudflareが「AI学習用」と分類するクローラーをWAFレベルでブロックする。検索エンジンやAIアシスタントは対象外&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;AI Labyrinth&lt;&#x2F;td&gt;&lt;td&gt;欺瞞防御&lt;&#x2F;td&gt;&lt;td&gt;ブロックを無視するクローラーに偽コンテンツを読ませ、学習データを汚染させるハニーポット&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;ポイントは、Content Signals PolicyとBlock AI botsの役割分担です。Content Signals Policyでは &lt;code&gt;search=yes, ai-input=yes, ai-train=no&lt;&#x2F;code&gt; のように宣言し、「検索やAI回答での引用はOKだが、モデルの学習には使うな」という意思を伝えます。しかし宣言はあくまで「お願い」なので、AI学習用クローラーに対してはBlock AI botsがWAFレベルで実際にアクセスを遮断します。それでもすり抜けてくるクローラーにはAI Labyrinthが偽データを食わせます。&lt;&#x2F;p&gt;
&lt;p&gt;さらに、AI Crawl ControlのCrawlersタブではクローラーごとに個別のAllow&#x2F;Blockを設定できます。たとえば「ChatGPT-Userは許可するがBytespiderはブロックする」といった細かい制御も可能です。&lt;&#x2F;p&gt;
&lt;p&gt;この多層構成により、AI検索からの流入を確保しつつ学習目的のスクレイピングは拒否するという運用が、無料プランだけで実現できます。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;Cloudflareの評価&quot;&gt;Cloudflareの評価&lt;&#x2F;h2&gt;
&lt;p&gt;比較表を振り返ると、Cloudflareの強みは大きく3つあります。&lt;&#x2F;p&gt;
&lt;p&gt;1つ目は、無料プランでのセキュリティの充実度です。AWSで同等のボット対策やWAFを実現しようとすると、AWS WAFやBot Controlの追加費用と自前でのルール作成が必要でした。GitHub Pagesではユーザーが設定できるセキュリティ機能はほとんどありません。Cloudflareでは、AIボットのブロック、Bot fight mode、WAFまで無料プランに含まれており、しかもダッシュボードのトグルひとつで有効にできます。&lt;&#x2F;p&gt;
&lt;p&gt;2つ目は、DNS・証明書・セキュリティ・CDNがひとつのダッシュボードに統合されている点です。AWSではRoute 53、CloudFront、ACM、WAFと複数サービスをまたいで設定する必要がありました。GitHub PagesではDNSが外部依存のため、DNSSECやSPF&#x2F;DMARCの設定は利用するDNSプロバイダ次第でした。Cloudflareではドメイン取得からDNSSEC、メールセキュリティ、デプロイまで一箇所で完結するため、設定の見通しがよく管理も楽です。&lt;&#x2F;p&gt;
&lt;p&gt;3つ目は、他のサービスでは提供されていない独自機能です。前述のとおり、Content Signals PolicyからBlock AI bots、AI Labyrinthまで、AIクローラーへの多層的な対応が無料プランだけで揃います。加えて、Speculation Rules APIを活用したSpeed BrainやTLS 1.3の0-RTT再接続など、パフォーマンス面でも独自の機能が提供されています。特にAIクローラー対策は今後ますます重要になる領域であり、「意思表示」と「技術的ブロック」と「欺瞞防御」を組み合わせた構成がワンクリックで手に入るのは大きな安心感があります。&lt;&#x2F;p&gt;
&lt;p&gt;個人の静的サイトという用途では、Cloudflareの無料プランだけで「やりたいことが全部できる」状態になりました。以前はAWSの複数サービスを組み合わせて実現していたことが、Cloudflareではひとつのダッシュボードで、しかも無料で手に入ります。移行してよかったと素直に思います。&lt;&#x2F;p&gt;
&lt;!-- textlint-enable --&gt;
&lt;section class=&quot;footnotes&quot;&gt;
&lt;ol class=&quot;footnotes-list&quot;&gt;
&lt;li id=&quot;fn-2&quot;&gt;
&lt;p&gt;Cloudflare Pagesは現在、Cloudflare Workersとの&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;blog.cloudflare.com&#x2F;pages-and-workers-are-converging-into-one-experience&#x2F;&quot;&gt;統合が進んでいる&lt;&#x2F;a&gt;。将来的にはWorkersの静的アセット機能に一本化される見込みだが、Pages自体も引き続き利用可能。 &lt;a href=&quot;#fr-2-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li id=&quot;fn-1&quot;&gt;
&lt;p&gt;&lt;code&gt;.dev&lt;&#x2F;code&gt; ドメインはGoogleが管理しているTLDで、HSTS Preload ListにTLD単位で登録済みなので最初からHTTPSが強制される。 &lt;a href=&quot;#fr-1-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;&#x2F;section&gt;
</content>
        <summary type="html">Cloudflareの無料プランで利用できるWAF・ボット対策・AIクローラー対策などのセキュリティ機能を、AWS AmplifyやGitHub Pagesと比較しながら紹介します。</summary>
        </entry><entry xml:lang="en">
        <title>Zolaブログを新ドメイン取得 + Cloudflare移転</title>
        <published>2026-02-17T00:00:00+00:00</published>
        <updated>2026-02-17T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2026/02/migration-to-cloudflare/" type="text/html"/>
        <id>https://codedchords.dev/blog/2026/02/migration-to-cloudflare/</id>
        
            <content type="html">&lt;!-- textlint-disable --&gt;
&lt;div class=&quot;admonition note&quot;&gt;
    &lt;div class=&quot;admonition-icon admonition-icon-note&quot;&gt;&lt;&#x2F;div&gt;
    &lt;div class=&quot;admonition-content&quot;&gt;
        &lt;strong class=&quot;admonition-title&quot;&gt;NOTE&lt;&#x2F;strong&gt;
        &lt;p&gt;この記事は
&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;zenn.dev&#x2F;yostos&#x2F;articles&#x2F;migration-to-cloudflare&quot;&gt;Zenn.dev&lt;&#x2F;a&gt;
に掲載した記事の転載です。&lt;&#x2F;p&gt;

    &lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;!-- textlint-enable --&gt;
&lt;h2 id=&quot;TL;DR（Zola利用者向け）&quot;&gt;TL;DR（Zola利用者向け）&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;Cloudflare ProxyとGitHub Pagesの組み合わせでは、Let&#x27;s Encrypt証明書のHTTP-01チャレンジを妨げるリスクがある&lt;&#x2F;li&gt;
&lt;li&gt;Cloudflare PagesのCI&#x2F;CDはv2以降Zolaをサポートしていない（&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;cloudflare&#x2F;pages-build-image&#x2F;issues&#x2F;3&quot;&gt;issue #3&lt;&#x2F;a&gt;は2023年からOpen）。GitHub Actions + &lt;code&gt;wrangler deploy&lt;&#x2F;code&gt;で代替可能&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;はじめに&quot;&gt;はじめに&lt;&#x2F;h2&gt;
&lt;p&gt;以前、Amazon Amplify + Next.js + Tailwind CSSで運用していたブログをGitHub Pages + Zolaに移行しました。GitHub Pagesはシンプルで運用コストが低い一方、カスタムHTTPレスポンスヘッダーを設定できないという制約があります。&lt;a href=&quot;https:&#x2F;&#x2F;codedchords.dev&#x2F;blog&#x2F;2026&#x2F;02&#x2F;github-pages-security-headers&#x2F;&quot;&gt;以前の記事&lt;&#x2F;a&gt;でも書きましたが、セキュリティスキャナーで警告が出る状態をずっと気にしていました。&lt;&#x2F;p&gt;
&lt;p&gt;では、Cloudflareに持っていくかと移転をはじめたところ、いくつかひっかかりポイントがあったので共有します。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;新ドメインの取得&quot;&gt;新ドメインの取得&lt;&#x2F;h2&gt;
&lt;p&gt;移転にあたり、新ドメイン&lt;code&gt;codedchords.dev&lt;&#x2F;code&gt;を取得しました。旧ドメインから変更した理由は2つあります。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Cloudflareの無料プランではDNSをCloudflareに移管する必要がある。旧ドメインはFastMailでメール運用しておりDNSもFastMailに移管済みのため、Cloudflareへの再移管が難しい&lt;&#x2F;li&gt;
&lt;li&gt;旧ドメインは長年の運用とブログ改築の結果、404でインデックスされないページが多数あり、これを機に一新してもよい&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;TLDは&lt;code&gt;.dev&lt;&#x2F;code&gt;を選びました。&lt;code&gt;.dev&lt;&#x2F;code&gt;はGoogleが管理するTLDで、HSTSプリロードリストに登録されています。ブラウザレベルでHTTPS接続が強制されるため、セキュリティ面で最初から一段高い状態が保証されます。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;Cloudflare_Workers_への移行&quot;&gt;Cloudflare Workers への移行&lt;&#x2F;h2&gt;
&lt;p&gt;セキュリティヘッダーを設定するために、Cloudflareを利用する方針で検討を進めました。最終的にCloudflare Workersの静的アセット機能に落ち着くまでに、2つのアプローチで挫折しています。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;案1: Cloudflare Proxy + Transform Rules（断念）&lt;&#x2F;strong&gt;。最初に検討したのは、CloudflareのProxyを有効にしてTransform Rulesでレスポンスヘッダーを追加する方法です。GitHub Pagesをオリジンとし、Cloudflareを前段に配置する構成です。しかし、GitHub PagesのLet&#x27;s Encrypt証明書は90日ごとにHTTP-01チャレンジで自動更新されます。Cloudflare Proxyが間に入るとチャレンジがGitHubへ届かず、更新が静かに失敗する可能性があります。証明書の期限切れでサイトが突然表示不能になるリスクがあり、静的ブログで証明書を定期監視するのは割に合いません。この案は見送りました。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;案2: Cloudflare Pages CI&#x2F;CD（断念）&lt;&#x2F;strong&gt;。次に、Cloudflare PagesのCI&#x2F;CDでZolaをビルドしてそのままホスティングする方法を試みました。しかし、Cloudflare Pagesのv2ビルドシステムではZolaがサポート対象から外れており、ビルドが通りません。この問題は&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;cloudflare&#x2F;pages-build-image&#x2F;issues&#x2F;3&quot;&gt;GitHubのissue&lt;&#x2F;a&gt;で2023年から報告されていますが、2026年2月現在もOpenのままです。リポジトリにZolaバイナリを同梱するワークアラウンドも提案されていますが、スマートとは言えないためこの案も断念しました。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;案3: Cloudflare Workers 静的アセット（採用）&lt;&#x2F;strong&gt;。最終的に採用したのが、Cloudflare Workersの静的アセット機能です。CloudflareはWorkersとPagesを統合する方針で、今後の機能開発はWorkersに集中されます。Workersの静的アセット機能は&lt;code&gt;_headers&lt;&#x2F;code&gt;ファイルをネイティブにサポートしており、セキュリティヘッダーの設定が可能です。SSL証明書もCloudflareが一元管理するため更新の問題は発生しません。ビルドはGitHub Actionsで行い、&lt;code&gt;wrangler deploy&lt;&#x2F;code&gt;でデプロイする構成にしました。Zolaのバージョンも自分で管理できます。&lt;&#x2F;p&gt;
&lt;p&gt;移行手順は以下のとおりです。&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Cloudflare DashboardのWorkers &amp;amp; Pagesから「Upload your static files」でプロジェクトを作成。後で上書きされるので適当なファイルを1つアップロードするだけでよい&lt;&#x2F;li&gt;
&lt;li&gt;既存のGitHub Actionsワークフロー（&lt;code&gt;deploy.yml&lt;&#x2F;code&gt;）を修正。Zolaのビルド部分はそのまま流用し、デプロイ先をCloudflare Workersに変更する。リポジトリに&lt;code&gt;wrangler.toml&lt;&#x2F;code&gt;を追加し、GitHub Repository SecretsにCloudflareのアカウントIDとAPIトークンを登録&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;yaml&quot; data-name=&quot;deploy.yml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;name&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; Deploy to Cloudflare Workers&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-constant z-language z-boolean&quot;&gt;on&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;  push&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;    branches&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;      -&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; main&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;  workflow_dispatch&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;permissions&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;  contents&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; read&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;concurrency&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;  group&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;deploy&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;  cancel-in-progress&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language z-boolean&quot;&gt; false&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;jobs&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;  deploy&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;    runs-on&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; ubuntu-latest&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;    steps&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;      -&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt; name&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; Checkout&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;        uses&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; actions&#x2F;checkout@v4&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;        with&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;          submodules&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; recursive&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;      -&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt; name&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; Setup Zola&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;        uses&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; taiki-e&#x2F;install-action@v2&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;        with&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;          tool&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; zola@0.22.1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;      -&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt; name&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; Build&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;        run&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; zola build&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;      -&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt; name&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; Deploy to Cloudflare&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;        uses&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; cloudflare&#x2F;wrangler-action@v3&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;        with&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;          apiToken&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; ${{ secrets.CLOUDFLARE_API_TOKEN }}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;          accountId&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;          wranglerVersion&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;4&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;          command&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; deploy&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;Workersにカスタムドメイン&lt;code&gt;codedchords.dev&lt;&#x2F;code&gt;を追加。CloudflareがDNSレコードを自動設定してくれる&lt;&#x2F;li&gt;
&lt;li&gt;GitHub Pagesを無効にする。Settings → PagesでSourceをNoneに変更するが、GitHub Actionsが選択されている状態ではNoneに変更できないため、一度Branchに切り替えてから設定する&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;移転後はGoogle Search Consoleに新ドメインのプロパティを追加し、サイトマップを送信しました。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;セキュリティヘッダーの設定&quot;&gt;セキュリティヘッダーの設定&lt;&#x2F;h2&gt;
&lt;p&gt;Cloudflare Workersの静的アセット機能は、ビルド出力に&lt;code&gt;_headers&lt;&#x2F;code&gt;ファイルを含めるとレスポンスヘッダーに自動適用します。Zolaの&lt;code&gt;static&#x2F;_headers&lt;&#x2F;code&gt;に以下を配置しました。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;plain&quot; data-name=&quot;static&#x2F;_headers&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;*&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  X-Content-Type-Options: nosniff&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  X-Frame-Options: DENY&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  Referrer-Policy: strict-origin-when-cross-origin&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  Permissions-Policy: camera=(), microphone=(), geolocation=()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;CSPは見送りました。SoundCloud、YouTube、OpenStreetMap、GoatCounter、Giscus、はてなブログカードなど外部リソースが多く、許可リストの管理コストに対して静的サイトでの実益が限定的なためです。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;旧ドメインからの転送&quot;&gt;旧ドメインからの転送&lt;&#x2F;h2&gt;
&lt;p&gt;旧ドメインへのアクセスを新ドメインに転送する必要があります。旧ドメインのDNSはFastMailで管理しておりCloudflareへの移行は行わないため、Cloudflare Redirect Rulesは使えません。&lt;&#x2F;p&gt;
&lt;p&gt;そこで、リダイレクト専用の静的サイトを生成する方法をとりました。Zolaで&lt;code&gt;zola build&lt;&#x2F;code&gt;すると全ページのHTMLが生成されます。aliasesによるリダイレクトページも含まれるため、以前Next.jsで運用していた時代のパスもカバーされます。この全HTMLをmeta refreshリダイレクトページに差し替えて、別リポジトリに配置し、旧ドメインでGitHub Pages配信する構成です。&lt;&#x2F;p&gt;
&lt;p&gt;各リダイレクトページの内容は以下のようになります。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;html&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-tag z-entity z-name z-tag&quot;&gt;&amp;lt;!DOCTYPE&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-other z-attribute-name&quot;&gt; html&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;html&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;  &amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;head&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;    &amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;meta&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-other z-attribute-name&quot;&gt; charset&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;utf-8&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt; &#x2F;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;    &amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;link&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-other z-attribute-name&quot;&gt; rel&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;canonical&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-other z-attribute-name&quot;&gt; href&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;https:&#x2F;&#x2F;codedchords.dev&#x2F;（対応パス）&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt; &#x2F;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;    &amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;meta&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-other z-attribute-name&quot;&gt;      http-equiv&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;refresh&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-other z-attribute-name&quot;&gt;      content&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;0; url=https:&#x2F;&#x2F;codedchords.dev&#x2F;（対応パス）&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;    &#x2F;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;  &amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;head&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;  &amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;body&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;gt;&amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;body&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;html&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Pythonスクリプトで、Zolaビルドからリダイレクトページの差し替え、不要ファイルの削除、CNAME配置までを一括実行しています。通常ページ367件とaliasページ226件、合計593件のリダイレクトを生成しました。aliasページはZolaが生成したmeta refreshのリダイレクト先（正規パス）を読み取り、新ドメインの正規パスに直接転送します。GitHub Actionsでデプロイを自動化しています。&lt;&#x2F;p&gt;
&lt;p&gt;この方法であれば全ページ・全パスをカバーできます。GitHub Pagesではサーバーサイドの301リダイレクトが設定できないため、meta refresh + canonicalの組み合わせが現実的な最善策です。FastMailのDNS変更も不要で、既存のCNAME&#x2F;Aレコードをそのまま利用できます。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;まとめ&quot;&gt;まとめ&lt;&#x2F;h2&gt;
&lt;p&gt;GitHub PagesからCloudflare Workersへの移転で得た知見をまとめます。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Cloudflare ProxyとGitHub Pagesの組み合わせでは、Let&#x27;s Encrypt証明書のHTTP-01チャレンジを妨げるリスクがある&lt;&#x2F;li&gt;
&lt;li&gt;Cloudflare PagesのCI&#x2F;CDはv2以降Zolaをサポートしていない（&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;cloudflare&#x2F;pages-build-image&#x2F;issues&#x2F;3&quot;&gt;issue #3&lt;&#x2F;a&gt;は2023年からOpen）。GitHub Actions + &lt;code&gt;wrangler deploy&lt;&#x2F;code&gt;で代替可能&lt;&#x2F;li&gt;
&lt;li&gt;Cloudflare Workersの静的アセット機能は&lt;code&gt;_headers&lt;&#x2F;code&gt;ファイルでセキュリティヘッダーを簡単に設定できる&lt;&#x2F;li&gt;
&lt;li&gt;旧ドメインからの転送は、meta refreshリダイレクトの静的サイトを生成する方法で全パスをカバーできる&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;&lt;code&gt;.dev&lt;&#x2F;code&gt;ドメインのHSTSプリロードに加え、Cloudflare Workers側でセキュリティヘッダーも設定できるようになり、セキュリティスキャナーの警告も解消されました。&lt;&#x2F;p&gt;
</content>
        <summary type="html">GitHub PagesからCloudflare Workersへブログを移転した際の落とし穴と解決策を共有します。証明書更新やZolaビルド非対応など、3つのアプローチを検討した経験をまとめています。
</summary>
        </entry><entry xml:lang="en">
        <title>生成AIラッパーサービスが罠である理由</title>
        <published>2026-02-17T00:00:00+00:00</published>
        <updated>2026-02-17T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2026/02/why-genai-wrapper-services-are-a-trap/" type="text/html"/>
        <id>https://codedchords.dev/blog/2026/02/why-genai-wrapper-services-are-a-trap/</id>
        
            <content type="html">&lt;!-- textlint-disable --&gt;
&lt;div class=&quot;admonition note&quot;&gt;
    &lt;div class=&quot;admonition-icon admonition-icon-note&quot;&gt;&lt;&#x2F;div&gt;
    &lt;div class=&quot;admonition-content&quot;&gt;
        &lt;strong class=&quot;admonition-title&quot;&gt;NOTE&lt;&#x2F;strong&gt;
        &lt;p&gt;この記事は
&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;zenn.dev&#x2F;yostos&#x2F;articles&#x2F;why-genai-wrapper-services-are-a-trap&quot;&gt;Zenn.dev&lt;&#x2F;a&gt;
に掲載した記事の転載です。&lt;&#x2F;p&gt;

    &lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;!-- textlint-enable --&gt;
&lt;!-- textlint-disable --&gt;
&lt;img
  src=&quot;https:&amp;#x2F;&amp;#x2F;codedchords.dev&amp;#x2F;blog&amp;#x2F;2026&amp;#x2F;02&amp;#x2F;why-genai-wrapper-services-are-a-trap&amp;#x2F;cover.webp?h=371fbdd60ae3bcfb751e&quot;
  alt=&quot;Cover&quot; width=&quot;1456&quot; height=&quot;816&quot; loading=&quot;lazy&quot;
&#x2F;&gt;&lt;!-- textlint-enable --&gt;
&lt;details&gt;
&lt;summary&gt;Table of Contents&lt;&#x2F;summary&gt;
&lt;!-- toc --&gt;
&lt;&#x2F;details&gt;
&lt;span id=&quot;continue-reading&quot;&gt;&lt;&#x2F;span&gt;
&lt;p&gt;生成AIを業務に導入したいが、ChatGPTやClaudeを直接使わせるのはセキュリティ上不安がある。そんな企業の声に応えるかたちで、「安全に使える法人向け生成AIサービス」を謳うサービスが次々と登場しています。&lt;&#x2F;p&gt;
&lt;p&gt;身近で話題に登ったことをきっかけに調べてみた、ちばぎんコンピューターサービスが提供する「C-chatSupport」もそのひとつです。&lt;&#x2F;p&gt;
&lt;!-- textlint-disable --&gt;
&lt;iframe class=&quot;hatenablogcard&quot; src=&quot;https:&#x2F;&#x2F;hatenablog-parts.com&#x2F;embed?url=https:&amp;#x2F;&amp;#x2F;www.ccsnet.co.jp&amp;#x2F;service&amp;#x2F;c-chatsupport&amp;#x2F;&quot; width=&quot;100%&quot; height=&quot;155&quot; frameborder=&quot;0&quot; scrolling=&quot;no&quot; loading=&quot;lazy&quot;&gt;&lt;&#x2F;iframe&gt;
&lt;!-- textlint-enable --&gt;
&lt;p&gt;本記事では、このサービスの公開情報をもとに技術者の視点から、この種の「ラッパーサービス」に共通する構造的な問題点を整理します。&lt;&#x2F;p&gt;
&lt;!-- textlint-disable --&gt;
&lt;div class=&quot;admonition warning&quot;&gt;
    &lt;div class=&quot;admonition-icon admonition-icon-warning&quot;&gt;&lt;&#x2F;div&gt;
    &lt;div class=&quot;admonition-content&quot;&gt;
        &lt;strong class=&quot;admonition-title&quot;&gt;WARNING&lt;&#x2F;strong&gt;
        &lt;p&gt;以下の分析はすべて2026年2月時点のWebサイト上の公開情報にもとづく筆者個人の見解であり、サービスの内部実装を直接検証したものではありません。実際のサービスには公開されていない機能や価格優位性がある可能性があります。導入を検討される際は、各サービス提供者の最新情報を直接ご確認ください。&lt;&#x2F;p&gt;

    &lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;!-- textlint-enable --&gt;
&lt;h2 id=&quot;本質的に「APIラッパー」にすぎない&quot;&gt;本質的に「APIラッパー」にすぎない&lt;&#x2F;h2&gt;
&lt;p&gt;この種のサービスの実態は、OpenAIやAnthropicなどの既存LLM APIにRAG機能とWebUIを被せたものです。独自のモデルや技術的な差別化要素は見当たりません。&lt;&#x2F;p&gt;
&lt;p&gt;C-chatSupportの場合、Webサイトでは「複数の生成AIモデルが利用可能」と謳っていますが、具体的なモデル名は一切記載されていません。アーキテクチャ図、データフローの説明、API仕様、SLAといった技術情報も公開されていません。公式ブログやプロモーション動画でもRAGを「社内情報からも参照して回答させる技術」と一般的な用語説明に留まり、自社実装の独自性には触れていません。紹介されている「メール作成時間75%削減」といった効果も、ChatGPTやClaudeを直接使えば同様に得られるものです。&lt;&#x2F;p&gt;
&lt;p&gt;技術者の立場から見ると、これは独自技術がないことの裏返しと判断せざるを得ません。自社開発の技術があれば、それこそが最大の差別化ポイントであり、積極的に公開するはずです。&lt;&#x2F;p&gt;
&lt;p&gt;ChatGPT Business、Claude Team、Microsoft Copilotといった一次提供者のサービスは、利用可能なモデル、性能ベンチマーク、データの取り扱いポリシー、コンプライアンス認証などを詳細に公開しています。技術的な透明性を担保できないサービスを、あえて間に挟む合理性はありません。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;価格設定への疑問&quot;&gt;価格設定への疑問&lt;&#x2F;h2&gt;
&lt;p&gt;C-chatSupportの場合、月額5万円（キャンペーン価格、通常7万円）で50ユーザーまで利用可能で、さらに従量料金が別途かかります。一見すると安価に見えますが、他のサービスと50ユーザーの月額基本料金で比較してみます（海外サービスは1ドル=約150円で換算）。&lt;&#x2F;p&gt;
&lt;!-- textlint-disable --&gt;


&lt;noscript&gt;
    &lt;strong&gt;⚠️ JavaScript is required to render the diagram.&lt;&#x2F;strong&gt;
&lt;&#x2F;noscript&gt;
&lt;pre class=&quot;mermaid invertible-image&quot;&gt;
    xychart-beta
title &quot;50ユーザーの月額基本料金（万円）&quot;
x-axis [&quot;C-chatSupport&quot;, &quot;ChatGPT Business&quot;, &quot;Claude Team&quot;, &quot;M365 Copilot&quot;]
y-axis &quot;万円&quot; 0 --&gt; 25
bar [5, 19, 19, 23]
&lt;&#x2F;pre&gt;
&lt;!-- textlint-enable --&gt;
&lt;p&gt;C-chatSupportの基本料金は確かに最安値です。しかし、これには従量課金が含まれていません。従量料金の単価も非公開のため、実際の月額コストは利用量次第で大きく変動します。一方、他のサービスは基本的に定額制です。なお、M365 CopilotはMicrosoft 365 E3&#x2F;E5等のベースライセンスが別途必要であり、実際のコストはグラフの金額より高くなります。&lt;&#x2F;p&gt;
&lt;p&gt;さらに重要なのは、この価格で得られる機能の差です。&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;機能&lt;&#x2F;th&gt;&lt;th style=&quot;text-align: center&quot;&gt;C-chatSupport&lt;&#x2F;th&gt;&lt;th style=&quot;text-align: center&quot;&gt;ChatGPT Business&lt;&#x2F;th&gt;&lt;th style=&quot;text-align: center&quot;&gt;Claude Team&lt;&#x2F;th&gt;&lt;th style=&quot;text-align: center&quot;&gt;M365 Copilot&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;チャット&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;○&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;○&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;○&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;○&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;RAG&#x2F;ナレッジ&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;○&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;○&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;○&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;○&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;画像生成&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;-&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;○&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;-&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;○&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;コード実行&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;-&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;○&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;○&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;-&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Office連携&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;-&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;-&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;-&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;○&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;管理コンソール&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;非公開&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;○&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;○&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;○&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;SLA&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;非公開&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;○&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;○&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;99.9%&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;料金体系&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;基本+従量&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;定額&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;定額&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: center&quot;&gt;定額&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;基本料金だけを見ると安く映りますが、従量課金を含めたトータルコストと機能差を考慮すると、割高になる可能性が高いです。特に「従量料金が非公開」という点は、予算管理の観点からも大きなリスクです。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;セキュリティの訴求が誤解を招く&quot;&gt;セキュリティの訴求が誤解を招く&lt;&#x2F;h2&gt;
&lt;p&gt;この種のサービスは「情報漏洩リスク無し」「社外にデータを出さない」といったセキュリティを前面に押し出す傾向があります。しかし、複数の生成AIモデルを利用可能としている以上、バックエンドではOpenAIやAnthropic等の外部APIを呼んでいるはずです。&lt;&#x2F;p&gt;
&lt;p&gt;「学習に使わない」という点はAPI利用規約上当然のことであり、このサービス固有の強みではありません。また「社外にデータを出さない」という表現は、APIリクエスト自体が外部サーバーへの通信を伴う以上、厳密には正確ではありません。Azure OpenAI Serviceのプライベートエンドポイントなどを使っている可能性はありますが、そうした技術的な裏付けの説明がない以上、顧客に誤った安心感を与えるリスクがあります。&lt;&#x2F;p&gt;
&lt;p&gt;技術的な根拠を示さずに「安全」を訴求するサービスは、むしろ警戒すべきです。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;機能の陳腐化リスク&quot;&gt;機能の陳腐化リスク&lt;&#x2F;h2&gt;
&lt;p&gt;紹介されているユースケース（議事録作成、DM作成、データ分析、マクロ生成）は、ChatGPT、Copilot、Claude等の汎用AIサービスで既にできることばかりです。&lt;&#x2F;p&gt;
&lt;p&gt;LLMの進化は非常に速く、ラッパーサービスは元のモデル提供者が同等機能をネイティブに実装した時点で価値を失います。実際、RAGについてもClaude、ChatGPT、Geminiのいずれもファイルアップロードとナレッジ検索を標準機能として提供済みです。ラッパーの「付加価値」は、モデル提供者自身がすぐに追い越してしまいます。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;ベンダーロックインと発展性の懸念&quot;&gt;ベンダーロックインと発展性の懸念&lt;&#x2F;h2&gt;
&lt;p&gt;地銀グループのSIer子会社のように、AI技術が本業ではない提供元の場合、開発リソースや投資規模は限られます。LLM分野のイノベーション速度に追随し続けられるかは疑問です。&lt;&#x2F;p&gt;
&lt;p&gt;また、導入後に乗り換えたくなった場合、RAGに蓄積したナレッジデータのポータビリティも不透明です。独自フォーマットでロックインされていれば、移行コストは高くつきます。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;乱立するラッパーサービス&quot;&gt;乱立するラッパーサービス&lt;&#x2F;h2&gt;
&lt;p&gt;この種のラッパーサービスは市場に溢れかえっています。&lt;&#x2F;p&gt;
&lt;p&gt;AIsmileyが2025年10月に公開した「生成AIチャットボットカオスマップ」には、国内だけで140製品以上が掲載されています。デロイト トーマツ ミック経済研究所の調査によると、法人向け生成AI導入ソリューション市場は2024年度の330億円から2025年度は503億円（前年比152%）、2026年度は720億円（同143%）へと急拡大しています。この成長市場を狙って、SIerやIT企業が「法人向け生成AIチャット」を次々と投入しているのが現状です。&lt;&#x2F;p&gt;
&lt;p&gt;なぜこれほどサービスが乱立するのか。理由は単純で、参入障壁が極めて低いからです。Difyのようなオープンソースの生成AIアプリ構築プラットフォームを使えば、RAG機能付きのチャットボットをノーコード・1日で構築できます。LLMのAPIキーを設定し、社内文書をアップロードし、チャットUIを公開する。技術的にはこれだけです。つまり、140以上のサービスの大半は、同じようなOSSやクラウドサービスの上に薄いカスタマイズを加えただけの可能性が高いということです。&lt;&#x2F;p&gt;
&lt;p&gt;参入障壁の低さは、撤退障壁の低さと表裏一体です。市場の飽和で採算が合わなくなれば、サービス終了のリスクも現実的です。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;まとめ&quot;&gt;まとめ&lt;&#x2F;h2&gt;
&lt;p&gt;組織が生成AIサービスの導入を検討する際には、「なぜChatGPT Business&#x2F;Enterprise、Claude Team、Microsoft Copilot、あるいはAmazon Bedrock上の自前構築ではなく、このサービスなのか」という問いに明確に答えられる必要があります。&lt;&#x2F;p&gt;
&lt;p&gt;唯一の合理的な理由があるとすれば、既存の取引関係や日本語でのサポート体制といった非技術的な要素でしょう。実際には「海外サービスはよく分からないから、馴染みのベンダーに任せよう」と、技術選定に関与しない経営層の判断で導入が決まるケースも多いのが実情です。しかし、その安心感がラッパーサービスの構造的な弱点に見合うコストかどうかは、慎重に見極めるべきです。&lt;&#x2F;p&gt;
&lt;p&gt;技術的な差別化が不明確なサービスへ毎月の利用料を支払い続けるよりも、ChatGPT Business、Claude Team、Copilotの直接契約、あるいはAmazon BedrockやAzure OpenAI Serviceによる自前構築のほうが、長期的にはコスト・機能の両面で有利です。「生成AIは難しそうだから専門家に任せたい」という不安に応えるだけのサービスへ、安易に飛びつかないことが重要です。&lt;&#x2F;p&gt;
</content>
        <summary type="html">生成AIの導入を急ぐ企業に向けた「ラッパーサービス」が増えています。既存LLMのAPIにUIを被せただけのサービスに潜む問題点を、価格・セキュリティ・将来性の観点から検証します。
</summary>
        </entry><entry xml:lang="en">
        <title>中小規模組織向け生成AIガイドラインサンプル</title>
        <published>2026-02-15T11:38:57+09:00</published>
        <updated>2026-02-15T11:38:57+09:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2026/02/genai-guideline-sample/" type="text/html"/>
        <id>https://codedchords.dev/blog/2026/02/genai-guideline-sample/</id>
        
            <content type="html">&lt;!-- image --&gt;
&lt;details&gt;
&lt;summary&gt;Table of Contents&lt;&#x2F;summary&gt;
&lt;!-- toc --&gt;
&lt;&#x2F;details&gt;
&lt;!-- textlint-disable --&gt;
&lt;img
  src=&quot;https:&amp;#x2F;&amp;#x2F;codedchords.dev&amp;#x2F;blog&amp;#x2F;2026&amp;#x2F;02&amp;#x2F;genai-guideline-sample&amp;#x2F;cover.webp?h=b5847dab37b3cf9136f1&quot;
  alt=&quot;cover&quot; width=&quot;1358&quot; height=&quot;761&quot; loading=&quot;lazy&quot;
&#x2F;&gt;&lt;!-- textlint-enable --&gt;
&lt;h2 id=&quot;TL;DR&quot;&gt;TL;DR&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;以前公開した
&lt;a href=&quot;&#x2F;blog&#x2F;2026&#x2F;01&#x2F;genai-governance-checklist-release&#x2F;&quot;&gt;生成AIガイドラインチェックリスト&lt;&#x2F;a&gt;
に基づき、具体例として参考にできる
サンプルガイドラインを作成し追加した&lt;&#x2F;li&gt;
&lt;li&gt;IT専門部署のない中小規模組織を想定した
&lt;strong&gt;大事故を防ぐ最低限を身の丈に合わせて
整えた60点ガイドライン&lt;&#x2F;strong&gt;&lt;&#x2F;li&gt;
&lt;li&gt;サンプルガイドラインの組織プロファイル・要件定義など
設計背景の文書もすべてリポジトリで公開。
カスタマイズの判断材料として使える&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;!-- textlint-disable --&gt;
&lt;iframe class=&quot;hatenablogcard&quot; src=&quot;https:&#x2F;&#x2F;hatenablog-parts.com&#x2F;embed?url=https:&amp;#x2F;&amp;#x2F;github.com&amp;#x2F;yostos&amp;#x2F;genai-governance-checklist&quot; width=&quot;100%&quot; height=&quot;155&quot; frameborder=&quot;0&quot; scrolling=&quot;no&quot; loading=&quot;lazy&quot;&gt;&lt;&#x2F;iframe&gt;
&lt;!-- textlint-enable --&gt;
&lt;h2 id=&quot;なぜサンプルを作ったのか&quot;&gt;なぜサンプルを作ったのか&lt;&#x2F;h2&gt;
&lt;p&gt;チェックリスト公開後、
「チェック項目の意図はわかったが、
具体的な書き方がわからないので実物を見せてほしい」
という声を多くいただきました。&lt;&#x2F;p&gt;
&lt;p&gt;チェックリストは
「何を書くべきか」を示すものですが、
「どう書くか」は組織の規模・業種・
リスク許容度によって大きく異なります。
前提が異なる例を見て意味があるのかという
疑問は大いにありますが、
「サンプルを見せて」というセリフは確かによく聞きます。
そこで特定の組織像を明確に設定したうえで、
そのまま実例として参照できるレベルの
サンプルガイドラインを作成しました。&lt;&#x2F;p&gt;
&lt;p&gt;前提がリテラシー・ガバナンスの低い組織なので、
完璧な例を作成しても実行不能でしょう。
当サンプルガイドラインは、
大事故を防ぐ最低限を
身の丈に合わせて整えた
60点を目指しています。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;前提条件&quot;&gt;前提条件&lt;&#x2F;h2&gt;
&lt;p&gt;このサンプルには明確な前提条件があります。&lt;&#x2F;p&gt;
&lt;p&gt;想定する組織は、
専門のIT部門を持たない中小規模の組織です。
&lt;code&gt;organization-profile.md&lt;&#x2F;code&gt; に記載した通り、
一般社団法人を想定しています。&lt;&#x2F;p&gt;
&lt;p&gt;こういった組織では独自に
生成AIを組み込んだシステムを
構築しづらいと考えます。
したがって、理事長などが無邪気に
「なんか生成AIいいらしいから、
ChatGPTを導入しよう」
みたいな担当者にとっては
地獄のようなシーンを想定しています。&lt;&#x2F;p&gt;
&lt;p&gt;こうした組織ではガイドラインを
まじめに一から作ることは稀で、
どこかから持ってきたものを
そのまま使う傾向があります。
だからこそ具体例として参考にできる水準の
サンプルを提供しています。&lt;&#x2F;p&gt;
&lt;p&gt;自組織への適用を検討する際は、
以下の前提が合致するかを
必ず確認してください。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;ChatGPT Team、Claude、Geminiなど
組織向け有料プランを利用する。
無料・個人プランは対象外&lt;&#x2F;li&gt;
&lt;li&gt;自社システムやSaaSに組み込まれるような
生成AIは想定していない&lt;&#x2F;li&gt;
&lt;li&gt;セキュリティやシステム管理の規定が
存在しないか、実効性がない&lt;&#x2F;li&gt;
&lt;li&gt;リテラシーが低く、かなり一般的なレベルから説明が必要&lt;&#x2F;li&gt;
&lt;li&gt;AI専任の管理者は置けず、
総務担当者などが兼務する運用体制&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;サンプルガイドラインの概要&quot;&gt;サンプルガイドラインの概要&lt;&#x2F;h2&gt;
&lt;p&gt;リポジトリの &lt;code&gt;docs&#x2F;guideline-sample&#x2F;&lt;&#x2F;code&gt; には
サンプル本文だけでなく、
その背景となる文書も一式公開しています。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;organization-profile.md&lt;&#x2F;code&gt; —
想定組織の規模、業種、体制、
現在のAI利用状況、懸念事項を定義した
組織プロファイル&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;requirements-for-guideline.md&lt;&#x2F;code&gt; —
対象読者、文書設計の方針、
チェックリストとの対応方針を記載した
ガイドライン要件&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;guideline-sample.md&lt;&#x2F;code&gt; —
全10章構成のサンプルガイドライン本文&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;guideline-sample.html&lt;&#x2F;code&gt; —
pandocで変換済みのHTML版&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;Makefile&lt;&#x2F;code&gt; —
MarkdownからHTMLへの変換スクリプト。
pandocがあれば &lt;code&gt;make&lt;&#x2F;code&gt; で再生成できる&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;「なぜこの内容になったのか」を
追跡できるようにすることで、
自組織向けにカスタマイズする際の
判断材料にしていただくことが狙いです。&lt;&#x2F;p&gt;
&lt;p&gt;サンプルはチェックリストの
必須74項目と推奨19項目、
合計93項目をカバーしています。
全10章の構成は以下の通りです。&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;組織体制と役割&lt;&#x2F;li&gt;
&lt;li&gt;利用が許可されるAIサービス&lt;&#x2F;li&gt;
&lt;li&gt;利用が許可される範囲&lt;&#x2F;li&gt;
&lt;li&gt;データ入力の制限&lt;&#x2F;li&gt;
&lt;li&gt;AI出力の利用上の注意&lt;&#x2F;li&gt;
&lt;li&gt;リスク管理&lt;&#x2F;li&gt;
&lt;li&gt;教育・研修&lt;&#x2F;li&gt;
&lt;li&gt;インシデント対応&lt;&#x2F;li&gt;
&lt;li&gt;違反時の対応&lt;&#x2F;li&gt;
&lt;li&gt;ガイドラインの運用&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;特に第4章「データ入力の制限」では、
個人情報・機密情報・顧客情報・
認証情報・財務情報・人事情報・
法的保護情報の7分類について
具体例とともに禁止事項を定めています。
また匿名化の手順も示しており、
「何がダメで、どうすればいいのか」を
非エンジニアにも伝わるように記述しました。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;カスタマイズのポイント&quot;&gt;カスタマイズのポイント&lt;&#x2F;h2&gt;
&lt;p&gt;サンプルをそのまま使うのではなく、
自組織の状況に合わせた調整を推奨します。&lt;&#x2F;p&gt;
&lt;p&gt;許可するAIサービスの種類、
禁止情報の分類と具体例、
インシデント時の報告先と連絡体制は
最低限見直してください。
業種固有の規制がある場合
（医療、金融、教育など）は、
該当する法令への対応を追加する
必要があります。&lt;&#x2F;p&gt;
&lt;p&gt;リポジトリの組織プロファイルと
要件定義を自組織版に書き換えるところから
始めることをお勧めします。
前提を整理すれば、
ガイドライン本文の修正ポイントが
自ずと明確になります。&lt;&#x2F;p&gt;
&lt;!-- textlint-disable --&gt;
&lt;div class=&quot;admonition warning&quot;&gt;
    &lt;div class=&quot;admonition-icon admonition-icon-warning&quot;&gt;&lt;&#x2F;div&gt;
    &lt;div class=&quot;admonition-content&quot;&gt;
        &lt;strong class=&quot;admonition-title&quot;&gt;免責事項&lt;&#x2F;strong&gt;
        &lt;p&gt;本サンプルは情報提供を目的としており、
法的助言を構成するものではありません。
実際のガイドライン策定にあたっては、
自組織の法務担当者や外部の専門家に
確認のうえご利用ください。
組織の業種、規模、
取り扱う情報の性質によって
必要な対策は異なります。
本サンプルの利用によって生じた損害について、
筆者は一切の責任を負いません。&lt;&#x2F;p&gt;

    &lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;!-- textlint-enable --&gt;
&lt;h2 id=&quot;まとめ&quot;&gt;まとめ&lt;&#x2F;h2&gt;
&lt;p&gt;正直に書きます。&lt;&#x2F;p&gt;
&lt;p&gt;チェックリストを公開後、
「ガイドラインのサンプルがあれば」と言われました。
そこで組織プロファイルから要件定義まで
丁寧に文書化し、93項目をカバーした
サンプルガイドラインを提供しました。
HTML版や変換スクリプトまで付けました。&lt;&#x2F;p&gt;
&lt;p&gt;結果どうなったか。
結局、サンプル活用の労力すら惜しんで
まともな検討もなく、出来合いの他組織の
ガイドラインをコピーしたものが採用されました。&lt;&#x2F;p&gt;
&lt;p&gt;そもそもの発端を振り返れば、
組織としてAIで何を実現したいかという
ビジョンがあったわけではありません。
組織トップの「なんか生成AIいいらしいから
導入しよう」という思いつきです。
導入によって何を実現したいのかが
不明確なまま、具体的な計画もなく
号令だけが降ってくる。
よくある話ですが、
そんな動機で降ってきた仕事に
担当者がやる気を出せないのは
むしろ当然でしょう。&lt;&#x2F;p&gt;
&lt;p&gt;それでもこのサンプルを公開するのは、
同じような状況で困っている担当者が
他にもいると確信しているからです。
組織のトップが思いつきで
「生成AIのガイドライン作って」と
言い出すシーンは、
いまこの瞬間も日本中で
起きているはずです。&lt;&#x2F;p&gt;
&lt;p&gt;チェックリストとサンプルを
組み合わせて使っていただければ、
少なくとも60点のガイドラインは
作れます。
60点で始めて、
運用しながら改善していく。
完璧を待つより、
はるかに良い選択だと考えています。&lt;&#x2F;p&gt;
</content>
        <summary type="html">「具体的なガイドラインの例が欲しい」という声に
応えて、60点の生成AIガイドラインサンプルを
公開しました。IT専門部署のない中小規模組織を
想定し、チェックリストの93項目をカバーしています。
</summary>
        </entry><entry xml:lang="en">
        <title>Evolving the MAGI System from Majority Vote to Deliberative Democracy with Agent Teams</title>
        <published>2026-02-14T00:00:00+00:00</published>
        <updated>2026-02-14T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2026/02/super-magi-agent-team/" type="text/html"/>
        <id>https://codedchords.dev/blog/2026/02/super-magi-agent-team/</id>
        
            <content type="html">&lt;p&gt;This is an English translation of the original
Japanese article published on Zenn:
&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;zenn.dev&#x2F;yostos&#x2F;articles&#x2F;super-magi-agent-team&quot;&gt;&quot;Agent TeamsでMAGIシステムを討議民主制に進化させた&quot;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;details&gt;
&lt;summary&gt;Table of Contents&lt;&#x2F;summary&gt;
&lt;!-- toc --&gt;
&lt;&#x2F;details&gt;
&lt;h2 id=&quot;TL;DR&quot;&gt;TL;DR&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;Built &quot;Super MAGI,&quot; a decision-support plugin
that goes beyond the Evangelion-inspired MAGI
system, using Claude Code&#x27;s new Agent Teams
feature&lt;&#x2F;li&gt;
&lt;li&gt;Evolved from a simple majority-vote system to
a deliberative democracy where agents debate
and re-vote when opinions are split&lt;&#x2F;li&gt;
&lt;li&gt;The deliberation phase dramatically improves
the quality and depth of analysis.
In practice, this reasoning process is more
valuable than the final verdict itself&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;!-- textlint-disable --&gt;
&lt;iframe class=&quot;hatenablogcard&quot; src=&quot;https:&#x2F;&#x2F;hatenablog-parts.com&#x2F;embed?url=https:&amp;#x2F;&amp;#x2F;github.com&amp;#x2F;yostos&amp;#x2F;claude-code-plugins&quot; width=&quot;100%&quot; height=&quot;155&quot; frameborder=&quot;0&quot; scrolling=&quot;no&quot; loading=&quot;lazy&quot;&gt;&lt;&#x2F;iframe&gt;
&lt;!-- textlint-enable --&gt;
&lt;h2 id=&quot;Introduction&quot;&gt;Introduction&lt;&#x2F;h2&gt;
&lt;p&gt;When Claude Code introduced its plugin system,
many developers probably had the same thought.
&quot;Could I build the MAGI system
from Evangelion?&quot;
The idea of multiple AI agents analyzing
problems from different perspectives
and deciding by majority vote
is a perfect use case for plugins.
Quite a few people have published
their own MAGI-inspired plugins.&lt;&#x2F;p&gt;
&lt;p&gt;I was no exception.
Last year I built a MAGI plugin with
three independent AI agents,
each embodying a different persona:
scientist, mother, and woman.
Each analyzes a given problem from
its unique perspective,
and the system reaches a conclusion
by majority vote.
You can launch it simply by typing &lt;code&gt;&#x2F;magi&lt;&#x2F;code&gt;
in Claude Code,
optionally passing a topic as an argument
(e.g., &lt;code&gt;&#x2F;magi Should we adopt remote work or require office attendance?&lt;&#x2F;code&gt;).
What started as a fun experiment turned out
to be surprisingly practical.
It is particularly useful for reviewing
my own writing and code,
where it provides more diverse feedback
than asking a single AI.
It has become a tool I use daily.&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-self-review-1&quot;&gt;&lt;a href=&quot;#fn-self-review&quot;&gt;1&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Then Claude Code announced Agent Teams.
This feature lets agents exchange messages
with each other.
I immediately thought,
&quot;What if MAGI agents could debate
when they disagree?&quot;
Instead of just casting votes in isolation,
they could argue their positions.
This article introduces the design philosophy
and implementation of Super MAGI,
which evolves the system from
&quot;vote and done&quot; to
&quot;debate, then vote.&quot;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;The_Original_MAGI_System&quot;&gt;The Original MAGI System&lt;&#x2F;h2&gt;
&lt;p&gt;The original MAGI operates in three phases
as a simple majority-vote system:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Phase 1 (Problem Structuring):
The ARBITRATOR works with the user
to frame the problem as a binary choice:
proposition, premises, Option A, and Option B&lt;&#x2F;li&gt;
&lt;li&gt;Phase 2 (Parallel Independent Analysis):
Three agents are launched in parallel
via the Task tool.
Each analyzes and votes independently,
without seeing the others&#x27; work&lt;&#x2F;li&gt;
&lt;li&gt;Phase 3 (Final Ruling):
The ARBITRATOR tallies the votes
and presents the majority decision&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;codedchords.dev&#x2F;blog&#x2F;2026&#x2F;02&#x2F;super-magi-agent-team&#x2F;magi.webp&quot; alt=&quot;Original MAGI - three agents running parallel independent analysis&quot; &#x2F;&gt;
&lt;em&gt;Phase 2 execution screen. MELCHIOR,
BALTHASAR, and CASPER running
in parallel in the background&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;The three agents each have
distinct evaluation criteria:&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Agent&lt;&#x2F;th&gt;&lt;th&gt;Perspective&lt;&#x2F;th&gt;&lt;th&gt;Criteria&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;MELCHIOR&lt;&#x2F;td&gt;&lt;td&gt;Scientist&lt;&#x2F;td&gt;&lt;td&gt;Technical feasibility, efficiency, scalability, quality of evidence&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;BALTHASAR&lt;&#x2F;td&gt;&lt;td&gt;Mother&lt;&#x2F;td&gt;&lt;td&gt;Legal compliance, ethical validity, risk management, impact on the vulnerable&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;CASPER&lt;&#x2F;td&gt;&lt;td&gt;Woman&lt;&#x2F;td&gt;&lt;td&gt;Emotional impact, UX, trend alignment, empathy&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;This system had one problem:
when the vote split 2-to-1,
the minority opinion was merely recorded.
The dissenter had no chance to rebut
the majority.
Even if the minority held
an important argument,
it might never influence the conclusion.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;Super_MAGI_with_Agent_Teams&quot;&gt;Super MAGI with Agent Teams&lt;&#x2F;h2&gt;
&lt;p&gt;In February 2026, Claude Code announced
&quot;Agent Teams&quot; as a research
preview.&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-agent-teams-1&quot;&gt;&lt;a href=&quot;#fn-agent-teams&quot;&gt;2&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;
Previously, sub-agents could only work
independently.
With Agent Teams, agents can exchange messages
directly with each other.&lt;&#x2F;p&gt;
&lt;p&gt;When I saw this feature, I thought,
&quot;What happens if MAGI agents debate
when they disagree?&quot;&lt;&#x2F;p&gt;
&lt;p&gt;In the original MAGI,
a 2-to-1 split simply recorded
the minority opinion.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Original MAGI&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;!-- textlint-disable --&gt;


&lt;noscript&gt;
    &lt;strong&gt;⚠️ JavaScript is required to render the diagram.&lt;&#x2F;strong&gt;
&lt;&#x2F;noscript&gt;
&lt;pre class=&quot;mermaid invertible-image&quot;&gt;
    flowchart LR
  subgraph Phase2[&quot;Phase 2: Independent Analysis&quot;]
    M[MELCHIOR] --&gt; V1[Vote]
    B[BALTHASAR] --&gt; V2[Vote]
    C[CASPER] --&gt; V3[Vote]
  end
  V1 --&gt; T[Vote Result]
  V2 --&gt; T
  V3 --&gt; T
&lt;&#x2F;pre&gt;
&lt;!-- textlint-enable --&gt;
&lt;p&gt;With Agent Teams, the minority can directly
rebut the majority, debate the issues,
and then everyone re-votes.
This is &lt;strong&gt;an evolution from majority rule
to deliberative democracy&lt;&#x2F;strong&gt;.
This is the evolution to &lt;strong&gt;Super MAGI&lt;&#x2F;strong&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Super MAGI extends the original MAGI plugin
by adding a &quot;deliberation phase&quot; powered
by Agent Teams.
The deliberation phase activates only when
opinions are split.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Super MAGI (2-to-1 split)&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;!-- textlint-disable --&gt;


&lt;noscript&gt;
    &lt;strong&gt;⚠️ JavaScript is required to render the diagram.&lt;&#x2F;strong&gt;
&lt;&#x2F;noscript&gt;
&lt;pre class=&quot;mermaid invertible-image&quot;&gt;
    flowchart LR
  subgraph Phase2[&quot;Phase 2: Independent Analysis&quot;]
    M[MELCHIOR] --&gt; V1[Vote]
    B[BALTHASAR] --&gt; V2[Vote]
    C[CASPER] --&gt; V3[Vote]
  end
  V1 --&gt; T[Vote Result]
  V2 --&gt; T
  V3 --&gt; T
  T --&gt;|3-to-0| R[Re-vote Result]
  T --&gt;|2-to-1| Phase3
  subgraph Phase3[&quot;Phase 3: Deliberation&quot;]
    D[Structured Debate]
  end
  Phase3 --&gt; R
&lt;&#x2F;pre&gt;
&lt;!-- textlint-enable --&gt;
&lt;p&gt;Inside the structured debate, agents exchange
messages following a four-round protocol
where the minority rebuts the majority.&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Phase&lt;&#x2F;th&gt;&lt;th&gt;API Used&lt;&#x2F;th&gt;&lt;th&gt;Purpose&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;Phase 2 (Independent Analysis)&lt;&#x2F;td&gt;&lt;td&gt;Task tool (&lt;code&gt;run_in_background&lt;&#x2F;code&gt;)&lt;&#x2F;td&gt;&lt;td&gt;Each agent researches and votes independently without referencing others&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Phase 3 (Deliberation)&lt;&#x2F;td&gt;&lt;td&gt;Agent Teams (&lt;code&gt;TeamCreate&lt;&#x2F;code&gt; &#x2F; &lt;code&gt;SendMessage&lt;&#x2F;code&gt;)&lt;&#x2F;td&gt;&lt;td&gt;Majority and minority engage in a four-round structured debate, then re-vote&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;The order of &quot;think independently first,
then debate&quot; matters.
If agents debated from the start,
there would be a risk of groupthink,
with the loudest voice dominating.
By conducting independent analysis first,
we preserve diversity of perspectives,
then use Agent Teams&#x27; bidirectional
communication to deepen the discussion
quality.&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-realworld-1&quot;&gt;&lt;a href=&quot;#fn-realworld&quot;&gt;3&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;&lt;&#x2F;p&gt;
&lt;p&gt;When the vote is unanimous (3-to-0),
the deliberation phase is skipped
and the system behaves like the original.
Even in a 2-to-1 split, the system asks
the user whether to proceed with deliberation,
avoiding unnecessary token consumption.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;The_Four-Round_Structured_Debate_Protocol&quot;&gt;The Four-Round Structured Debate Protocol&lt;&#x2F;h2&gt;
&lt;p&gt;The heart of the deliberation phase is
a four-round structured debate protocol.&lt;&#x2F;p&gt;
&lt;!-- textlint-disable --&gt;


&lt;noscript&gt;
    &lt;strong&gt;⚠️ JavaScript is required to render the diagram.&lt;&#x2F;strong&gt;
&lt;&#x2F;noscript&gt;
&lt;pre class=&quot;mermaid invertible-image&quot;&gt;
    sequenceDiagram
  participant A as Majority A
  participant B as Majority B
  participant C as Minority
  Note over A,C: Round 1
  A-&gt;&gt;C: Present arguments
  B-&gt;&gt;C: Present arguments
  Note over A,C: Round 2
  C-&gt;&gt;A: Rebuttal
  C-&gt;&gt;B: Rebuttal
  Note over A,C: Round 3
  A-&gt;&gt;C: Counter-rebuttal
  B-&gt;&gt;C: Counter-rebuttal
  Note over A,C: Round 4
  C-&gt;&gt;A: Final rebuttal (last word)
  C-&gt;&gt;B: Final rebuttal (last word)
&lt;&#x2F;pre&gt;
&lt;!-- textlint-enable --&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Round&lt;&#x2F;th&gt;&lt;th&gt;Speaker&lt;&#x2F;th&gt;&lt;th&gt;Content&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;Round 1: Opening Arguments&lt;&#x2F;td&gt;&lt;td&gt;Majority to Minority&lt;&#x2F;td&gt;&lt;td&gt;Each majority agent presents their analysis and voting rationale to the minority&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Round 2: Rebuttal&lt;&#x2F;td&gt;&lt;td&gt;Minority to Majority&lt;&#x2F;td&gt;&lt;td&gt;The minority rebuts the majority&#x27;s arguments&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Round 3: Counter-Rebuttal&lt;&#x2F;td&gt;&lt;td&gt;Majority to Minority&lt;&#x2F;td&gt;&lt;td&gt;The majority responds to the minority&#x27;s rebuttal&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Round 4: Final Rebuttal&lt;&#x2F;td&gt;&lt;td&gt;Minority to Majority&lt;&#x2F;td&gt;&lt;td&gt;The minority delivers a final rebuttal. This is their last chance to speak&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;Procedural fairness is structurally
built into this protocol.&lt;&#x2F;p&gt;
&lt;p&gt;In Round 1, the majority presents
their arguments first to eliminate
information asymmetry.
The minority can construct their rebuttal
knowing exactly what evidence the majority
relied on.&lt;&#x2F;p&gt;
&lt;p&gt;In Round 4, the minority gets the last word
to compensate for their numerical
disadvantage.
The majority already holds the power
of two votes.
Giving the minority the final say prevents
conclusions from being reached
without the minority being able to respond
to the majority&#x27;s counter-rebuttals.
This design is grounded in the principle
J.S. Mill articulated against
the &quot;tyranny of the majority.&quot;&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-mill-1&quot;&gt;&lt;a href=&quot;#fn-mill&quot;&gt;4&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;&lt;&#x2F;p&gt;
&lt;p&gt;After four rounds of debate,
all agents cast their votes again.
If persuaded, agents may change
their positions.
The final output explicitly shows each
agent&#x27;s vote trajectory and reasons
for any changes.&lt;&#x2F;p&gt;
&lt;p&gt;When using tmux, the deliberation phase
automatically splits the screen
for each agent&#x27;s session, as shown below.
You can watch the agents working
independently while exchanging messages
in real time,
giving a genuine sense that they are
&quot;debating.&quot;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;codedchords.dev&#x2F;blog&#x2F;2026&#x2F;02&#x2F;super-magi-agent-team&#x2F;super-magi.webp&quot; alt=&quot;Super MAGI - deliberation phase execution screen with Agent Teams&quot; &#x2F;&gt;
&lt;em&gt;Deliberation phase execution screen&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;Graceful_Degradation&quot;&gt;Graceful Degradation&lt;&#x2F;h2&gt;
&lt;p&gt;Since Agent Teams is an experimental feature
in research preview,
Super MAGI is designed with graceful
degradation so it continues working
even when the feature is not fully available.
Specifically, it uses a hybrid architecture
combining traditional Task-tool-based
independent analysis with Agent Teams-based
structured debate.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;TeamCreate failure: Proceeds directly
to final ruling using Phase 2 vote results&lt;&#x2F;li&gt;
&lt;li&gt;Agent unresponsive: Retains the
unresponsive agent&#x27;s Phase 2 vote
and continues the debate with the rest&lt;&#x2F;li&gt;
&lt;li&gt;TeamDelete failure: Logs a warning
and executes the final ruling normally&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Every error path falls back to
&quot;Phase 2 independent analysis results.&quot;
Phase 2 results are generated
with guaranteed agent independence.
So even if deliberation fails,
decision quality is maintained at the same
level as the original MAGI.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;Case_Study:_What_Changes_with_the_Trolley_Problem&quot;&gt;Case Study: What Changes with the Trolley Problem&lt;&#x2F;h2&gt;
&lt;p&gt;To test Super MAGI in practice,
I evaluated the footbridge variant
of the trolley problem with both
the original MAGI and Super MAGI.
The proposition: &quot;A runaway trolley is heading
toward five workers.
Pushing Worker C off the bridge would stop
the trolley, but C would certainly die.
Should A push C?&quot;&lt;&#x2F;p&gt;
&lt;p&gt;The conclusion was the same in both cases.
MELCHIOR (Option A: push) versus BALTHASAR
and CASPER (Option B: do nothing),
with Option B adopted 2-to-1.
The voting pattern did not change.&lt;&#x2F;p&gt;
&lt;p&gt;What changed was the quality of reasoning
leading to the conclusion.&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Comparison&lt;&#x2F;th&gt;&lt;th&gt;Original MAGI&lt;&#x2F;th&gt;&lt;th&gt;Super MAGI&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;Depth of analysis&lt;&#x2F;td&gt;&lt;td&gt;One paragraph per agent&lt;&#x2F;td&gt;&lt;td&gt;MELCHIOR raised 8 counter-arguments; BALTHASAR cited 11 references&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Visibility of reasoning&lt;&#x2F;td&gt;&lt;td&gt;Final result only&lt;&#x2F;td&gt;&lt;td&gt;Full four-round rebuttal and counter-rebuttal process recorded&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Intellectual honesty&lt;&#x2F;td&gt;&lt;td&gt;Each agent simply stated their conclusion&lt;&#x2F;td&gt;&lt;td&gt;Majority explicitly acknowledged which of MELCHIOR&#x27;s points they accepted&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Treatment of minority&lt;&#x2F;td&gt;&lt;td&gt;Opinion merely recorded&lt;&#x2F;td&gt;&lt;td&gt;Developed sharp rebuttals such as &quot;the separation of law and morality&quot; and &quot;what would you say to the families of the five?&quot;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;What was particularly striking was that
the majority agents, BALTHASAR and CASPER,
acknowledged parts of minority MELCHIOR&#x27;s
arguments during the re-vote.
BALTHASAR conceded the partial effectiveness
of rule utilitarianism in avoiding
the organ harvesting problem.
CASPER acknowledged the validity
of pointing out Damasio&#x27;s circular reasoning.
They did not change their positions,
but they recognized the legitimate parts
of their opponent&#x27;s arguments.
This intellectual honesty does not emerge
from independent voting alone.&lt;&#x2F;p&gt;
&lt;p&gt;What Super MAGI delivered was not
&quot;a change in conclusion&quot; but
&quot;confirmation of the conclusion&#x27;s
robustness.&quot;
The fact that the conclusion held even
after debate increases confidence
in the decision.
Of course, there are cases where debate
could reverse the conclusion.&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-article-review-1&quot;&gt;&lt;a href=&quot;#fn-article-review&quot;&gt;5&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;
That is when the deliberation phase
truly proves its worth.&lt;&#x2F;p&gt;
&lt;p&gt;In practical use of MAGI, the analysis
presented during the reasoning process
is actually more useful than the final
&quot;Option A or Option B&quot; verdict.
What perspectives were considered,
which arguments proved effective,
and where the weaknesses lie.
The rebuttals and counter-rebuttals exchanged
during the deliberation phase
surface arguments I would never have
noticed on my own.
I believe MAGI&#x27;s true value lies not
in &quot;producing an answer&quot; but in
&quot;assembling the materials for thinking.&quot;&lt;&#x2F;p&gt;
&lt;p&gt;In terms of volume, the original MAGI
produces roughly 50 lines,
while Super MAGI generates about 220 lines,
more than four times as much.
Deep analysis and brevity are a trade-off,
which is why the design to skip deliberation
for unanimous votes proves valuable.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;Conclusion&quot;&gt;Conclusion&lt;&#x2F;h2&gt;
&lt;p&gt;Super MAGI leverages Claude Code&#x27;s Agent Teams
feature to evolve multi-agent decision-making
from &quot;vote and done&quot; to
&quot;debate, then vote.&quot;&lt;&#x2F;p&gt;
&lt;p&gt;Here are the key design principles:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Preserving independence: Analyze
independently first, then debate.
Maintaining this order preserves
diversity of perspectives&lt;&#x2F;li&gt;
&lt;li&gt;Selective activation: No deliberation needed
for unanimous votes.
Dig deeper only when opinions diverge&lt;&#x2F;li&gt;
&lt;li&gt;Structured fairness: Guarantee the minority
the last word, compensating for numerical
disadvantage through procedure&lt;&#x2F;li&gt;
&lt;li&gt;Safe fallback: All errors fall back
to independent analysis results&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;The plugin is available on GitHub.
If you are a Claude Code user,
you can install it and try the &lt;code&gt;&#x2F;magi&lt;&#x2F;code&gt;
command.&lt;&#x2F;p&gt;
&lt;section class=&quot;footnotes&quot;&gt;
&lt;ol class=&quot;footnotes-list&quot;&gt;
&lt;li id=&quot;fn-self-review&quot;&gt;
&lt;p&gt;The Super MAGI concept document and requirements specification were themselves reviewed by MAGI, both receiving unanimous 3-to-0 approval. The results are included in the repository&#x27;s &lt;code&gt;docs&#x2F;&lt;&#x2F;code&gt; directory. &lt;a href=&quot;#fr-self-review-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li id=&quot;fn-agent-teams&quot;&gt;
&lt;p&gt;Announced alongside Claude Opus 4.6. A single session acts as team leader, spawning multiple agents as teammates who exchange messages via &lt;code&gt;SendMessage&lt;&#x2F;code&gt;. See the &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;code.claude.com&#x2F;docs&#x2F;en&#x2F;agent-teams&quot;&gt;official documentation&lt;&#x2F;a&gt; for details. &lt;a href=&quot;#fr-agent-teams-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li id=&quot;fn-realworld&quot;&gt;
&lt;p&gt;If only the real world worked this way too. &lt;a href=&quot;#fr-realworld-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li id=&quot;fn-mill&quot;&gt;
&lt;p&gt;J.S. Mill, &lt;em&gt;On Liberty&lt;&#x2F;em&gt; (1859). Mill criticized the &quot;tyranny of the majority,&quot; arguing that even if all of humanity held one opinion and only a single person held the opposite, silencing that one person would not be justified. &lt;a href=&quot;#fr-mill-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li id=&quot;fn-article-review&quot;&gt;
&lt;p&gt;A reversal actually occurred during the review of this article. The initial vote split 2-to-1 (Option B: needs improvement), but after the deliberation phase, it reversed to a unanimous 3-to-0 (Option A: worthy of publication). &lt;a href=&quot;#fr-article-review-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;&#x2F;section&gt;
</content>
        <summary type="html">Using Claude Code&#x27;s Agent Teams feature,
I upgraded the Evangelion-inspired MAGI plugin
from simple majority voting
to a deliberative democracy system
where AI agents debate before casting
their final votes.
</summary>
        </entry><entry xml:lang="en">
        <title>Claude Codeの「何やってたっけ？」をなくす — jrnl-toolsで文脈を渡す</title>
        <published>2026-02-13T00:00:00+00:00</published>
        <updated>2026-02-13T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2026/02/claude-code-jrnl-context-handoff/" type="text/html"/>
        <id>https://codedchords.dev/blog/2026/02/claude-code-jrnl-context-handoff/</id>
        
            <content type="html">&lt;!-- textlint-disable --&gt;
&lt;div class=&quot;admonition info&quot;&gt;
    &lt;div class=&quot;admonition-icon admonition-icon-info&quot;&gt;&lt;&#x2F;div&gt;
    &lt;div class=&quot;admonition-content&quot;&gt;
        &lt;strong class=&quot;admonition-title&quot;&gt;転載記事&lt;&#x2F;strong&gt;
        &lt;p&gt;この記事は&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;zenn.dev&#x2F;yostos&#x2F;articles&#x2F;claude-code-jrnl-context-handoff&quot;&gt;Zenn&lt;&#x2F;a&gt;に掲載した記事の転載です。&lt;&#x2F;p&gt;

    &lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;!-- textlint-enable --&gt;
&lt;details&gt;
&lt;summary&gt;Table of Contents&lt;&#x2F;summary&gt;
&lt;!-- toc --&gt;
&lt;&#x2F;details&gt;
&lt;h2 id=&quot;TL;DR&quot;&gt;TL;DR&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;CLIジャーナルツール
&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;jrnl.sh&#x2F;&quot;&gt;jrnl&lt;&#x2F;a&gt;を使って
Claude Codeのセッション間で失われる
記憶を引き継ぐプラグイン
&lt;strong&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;yostos&#x2F;claude-code-plugins&#x2F;tree&#x2F;main&#x2F;plugins&#x2F;jrnl-plugin&quot;&gt;jrnl-tools&lt;&#x2F;a&gt;&lt;&#x2F;strong&gt;
を紹介&lt;&#x2F;li&gt;
&lt;li&gt;セッション終了時に&lt;code&gt;&#x2F;jrnl-handoff&lt;&#x2F;code&gt;で
作業状態を記録し、
翌日&lt;code&gt;&#x2F;jrnl-restore&lt;&#x2F;code&gt;で復元&lt;&#x2F;li&gt;
&lt;li&gt;プロジェクト横断の状況一覧や
時系列の作業履歴も可能&lt;&#x2F;li&gt;
&lt;li&gt;2026年2月5日にリリースされた
&lt;strong&gt;Auto Memory&lt;&#x2F;strong&gt;との棲み分けも解説&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;!-- textlint-disable --&gt;
&lt;iframe class=&quot;hatenablogcard&quot; src=&quot;https:&#x2F;&#x2F;hatenablog-parts.com&#x2F;embed?url=https:&amp;#x2F;&amp;#x2F;github.com&amp;#x2F;yostos&amp;#x2F;claude-code-plugins&quot; width=&quot;100%&quot; height=&quot;155&quot; frameborder=&quot;0&quot; scrolling=&quot;no&quot; loading=&quot;lazy&quot;&gt;&lt;&#x2F;iframe&gt;
&lt;!-- textlint-enable --&gt;
&lt;h2 id=&quot;きっかけ_—_MCPからプラグインへ、そして活用法の発見&quot;&gt;きっかけ — MCPからプラグインへ、そして活用法の発見&lt;&#x2F;h2&gt;
&lt;p&gt;Claude Codeで複雑なリファクタリングを
進めていて、
途中でセッションを閉じる必要がありました。
翌日セッションを再開すると、
Claude Codeは何も覚えていません。
「昨日の続きをお願い」と言っても、
ゼロから説明し直す羽目になりました。&lt;&#x2F;p&gt;
&lt;p&gt;筆者は以前から、
日々の作業を記録するために
&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;jrnl.sh&#x2F;&quot;&gt;jrnl&lt;&#x2F;a&gt;というCLIジャーナル
ツールを使っていました&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-jrnl-mcp-1&quot;&gt;&lt;a href=&quot;#fn-jrnl-mcp&quot;&gt;1&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;。
ターミナルから
&lt;code&gt;jrnl &quot;今日はXXを調査した&quot;&lt;&#x2F;code&gt;
と打つだけで記録が残る、
その手軽さを気に入っていたからです。&lt;&#x2F;p&gt;
&lt;p&gt;セッション記憶喪失の体験と、
普段使いのjrnl。
この2つが頭の中でつながりました。
&lt;strong&gt;jrnlが自分への備忘録として
機能するなら、Claude Codeへの備忘録としても
使えるのではないか。&lt;&#x2F;strong&gt;
セッション終了時にjrnlへ引き継ぎメモを書き、
翌日のセッションでそれを読み込ませれば、
文脈を引き継げるはずです。&lt;&#x2F;p&gt;
&lt;p&gt;このアイデアがjrnl-toolsプラグインの
出発点です。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;Claude_Codeの「記憶」の限界&quot;&gt;Claude Codeの「記憶」の限界&lt;&#x2F;h2&gt;
&lt;p&gt;Claude Codeは強力な開発パートナーです。
コードを読み、修正し、テストを回し、
アーキテクチャの議論まで
一緒にしてくれます。
しかし、セッション固有の文脈には
根本的な制約があります。&lt;&#x2F;p&gt;
&lt;p&gt;Claude Codeには&lt;code&gt;CLAUDE.md&lt;&#x2F;code&gt;という
永続的な設定ファイルがあり、
プロジェクトのルールや規約は
セッションを超えて引き継げます。
しかし、
&lt;strong&gt;「昨日のセッションで何を議論し、
どこまで進み、
次に何をする予定だったか」という
セッション固有のコンテキストは
引き継がれません。&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;昨日2時間かけてデバッグした
認証バグの調査過程、設計判断の理由、
「次にやること」の合意。
セッションを閉じた瞬間、それらは消えます。
翌朝、新しいセッションを開くと、
Claude Codeはプロジェクトのルールは
知っていても、
昨日の作業状況は知りません。&lt;&#x2F;p&gt;
&lt;p&gt;「それなら&lt;code&gt;claude --resume&lt;&#x2F;code&gt;や
&lt;code&gt;claude --continue&lt;&#x2F;code&gt;でセッションを
再開すればいいのでは？」
と思うかもしれません。
確かに、これらのコマンドは
会話履歴をそのまま復元できる
強力な機能です。
しかし、セッション再開には
以下の制約があります。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;同一ディレクトリ限定&lt;&#x2F;strong&gt; —
セッションはディレクトリに紐付いており、
別プロジェクトのセッションは
再開できない&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;コンテキストウィンドウの制約&lt;&#x2F;strong&gt; —
長いセッションはコンパクト化され、
過去の議論の詳細は失われていく&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;検索性がない&lt;&#x2F;strong&gt; —
「先月の認証バグ調査」を
後から探すことはできない。
セッション履歴は蓄積される
知識にならない。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;そもそも、
膨大に膨らんだセッションの
コンテキストをそのまま次回に
引き継ぎたいわけではありません。
必要なのは「何が完了し、何が残っていて、
次にどこから始めるか」という要点です。
セッション再開は「中断した作業の
直接的な続行」には向いていますが、
「要点を絞った引き継ぎ」や
「長期的な作業記録」には
対応していません。&lt;&#x2F;p&gt;
&lt;p&gt;さらに、
複数プロジェクトを並行して進めている
開発者にとって、問題は深刻です。
Claude Codeはプロジェクト
（ディレクトリ）単位で動作するため、
プロジェクトAで作業しているときに
プロジェクトBの状況を知る方法が
ありません。&lt;&#x2F;p&gt;
&lt;p&gt;つまり、足りていないのは以下の2つです。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;セッションの要点を構造化して
引き継ぐ仕組み&lt;&#x2F;strong&gt; —
何を議論し、どこまで進み、
次に何をするかを簡潔に次の
セッションに伝える手段&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;プロジェクトの壁を超えた
横断的な状況把握&lt;&#x2F;strong&gt; —
どのプロジェクトからでも、
他のプロジェクトの進捗を
確認できる手段&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;これらを既存のCLIツールで
実現できないかと考えたとき、
冒頭で触れたjrnlの存在が
頭に浮かびました。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;jrnlという選択_—_CLIジャーナルが架け橋になる&quot;&gt;jrnlという選択 — CLIジャーナルが架け橋になる&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;jrnl.sh&#x2F;&quot;&gt;jrnl&lt;&#x2F;a&gt; は
コマンドラインで動くシンプルな
ジャーナルツールです。
テキストベースで、タグ付けができ、
日付によるフィルタリングが可能です。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;jrnl&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;認証バグの原因はトークンリフレッシュ処理にあった @api @log&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;たったこれだけで、
タイムスタンプ付きのエントリが
記録されます。
このシンプルさがClaude Codeとの
統合に適しています。&lt;&#x2F;p&gt;
&lt;p&gt;jrnl-toolsが目指すのは、
&lt;strong&gt;jrnlをClaude Codeセッション間の
「フロー情報ハブ」にすること&lt;&#x2F;strong&gt;です。&lt;&#x2F;p&gt;
&lt;!-- textlint-disable --&gt;


&lt;noscript&gt;
    &lt;strong&gt;⚠️ JavaScript is required to render the diagram.&lt;&#x2F;strong&gt;
&lt;&#x2F;noscript&gt;
&lt;pre class=&quot;mermaid invertible-image&quot;&gt;
    graph TD
A[&quot;Project A&lt;br&#x2F;&gt;(Claude Code)&quot;] --&gt; J
B[&quot;Project B&lt;br&#x2F;&gt;(Claude Code)&quot;] --&gt; J
C[&quot;Project C&lt;br&#x2F;&gt;(Claude Code)&quot;] --&gt; J
J[&quot;jrnl (グローバル)&lt;br&#x2F;&gt;作業ログ &#x2F; ハンドオフ &#x2F; アイデア&quot;]
J --&gt; R[&quot;どのプロジェクトからでもアクセス可能&quot;]
&lt;&#x2F;pre&gt;
&lt;!-- textlint-enable --&gt;
&lt;p&gt;各プロジェクトのClaude Codeセッションから
jrnlに書き込み、
別のプロジェクトや翌日のセッションから
それを読み出す。
jrnlがプロジェクトとセッションの壁を超える
共有レイヤーになります。
組み込みのメモリ機能にはない、
jrnlならではの特性は以下の通りです。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;クロスプロジェクト横断&lt;&#x2F;strong&gt; —
jrnlはグローバルなので、
どのプロジェクトからでも
全プロジェクトの状況を把握できる&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;時系列の作業履歴&lt;&#x2F;strong&gt; —
エントリは日付付きで蓄積され、
後から検索・振り返りができる&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Claude Code外からもアクセス可能&lt;&#x2F;strong&gt; —
&lt;code&gt;jrnl @handoff&lt;&#x2F;code&gt;のように、
ターミナルから直接検索・閲覧できる&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;ユーザーが完全に制御可能&lt;&#x2F;strong&gt; —
エントリはプレーンテキストであり、
内容の確認・編集・削除を
自分で管理できる&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;「オリエンテーションガイド」という設計思想&quot;&gt;「オリエンテーションガイド」という設計思想&lt;&#x2F;h2&gt;
&lt;p&gt;jrnl-toolsの設計で
最も重要な考え方があります。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;ハンドオフは「状態のダンプ」ではなく
「オリエンテーションガイド」です。&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;最初は、セッションの全状態をjrnlに
保存しようと考えました。
しかし実際に使ってみると、
複雑なセッションほど圧縮されて
読みにくいエントリになり、
結局役に立ちません。&lt;&#x2F;p&gt;
&lt;p&gt;そこで発想を転換しました。
プロジェクトの詳細な状態は、
TODO.md、設計ドキュメント、
コード自体に既に存在しています。
次のセッションのAIに必要なのは
「どこを見ればいいか」
という案内図です。&lt;&#x2F;p&gt;
&lt;!-- textlint-disable --&gt;


&lt;noscript&gt;
    &lt;strong&gt;⚠️ JavaScript is required to render the diagram.&lt;&#x2F;strong&gt;
&lt;&#x2F;noscript&gt;
&lt;pre class=&quot;mermaid invertible-image&quot;&gt;
    graph LR
H[&quot;jrnl（オリエンテーションガイド）&lt;br&#x2F;&gt;Handoff:&lt;br&#x2F;&gt;TODO.md Phase 9を確認&lt;br&#x2F;&gt;issue #2に取り組み中&quot;] -- &quot;参照&quot; --&gt; P[&quot;プロジェクト文書（詳細な状態）&lt;br&#x2F;&gt;TODO.md&lt;br&#x2F;&gt;docs&#x2F;architecture.md&lt;br&#x2F;&gt;CLAUDE.md&lt;br&#x2F;&gt;ソースコード&quot;]
&lt;&#x2F;pre&gt;
&lt;!-- textlint-enable --&gt;
&lt;p&gt;良いハンドオフとは、
次のセッションが
「どのファイルを読めばいいか」
「何が進行中だったか」を
瞬時に把握できるものです。
すべてを記録する必要はありません。
プロジェクトファイルが永続的な状態を
持っているからです。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;jrnl-toolsの4つのコマンド&quot;&gt;jrnl-toolsの4つのコマンド&lt;&#x2F;h2&gt;
&lt;p&gt;jrnl-toolsプラグインは、
4つのスラッシュコマンドを提供します。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;&#x2F;jrnl-handoff_—_明日の自分への引き継ぎ&quot;&gt;&lt;code&gt;&#x2F;jrnl-handoff&lt;&#x2F;code&gt; — 明日の自分への引き継ぎ&lt;&#x2F;h3&gt;
&lt;p&gt;作業を終えるとき、
このコマンドを実行します。
Claude Codeがセッションの内容を分析し、
次のセッション向けの
オリエンテーションガイドを生成します。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&amp;gt; &#x2F;jrnl-handoff&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;生成されるエントリの例は
以下のようになります。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Handoff: 認証ミドルウェアのリファクタリング完了 @api-server @handoff&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Progress:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;- トークンリフレッシュロジックを修正（auth.ts:45-78）&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;- ログイン&#x2F;ログアウトフローのテストがパス&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Files changed:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;- src&#x2F;middleware&#x2F;auth.ts&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;- tests&#x2F;auth.test.ts&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Blockers:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;- None&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Next:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;- &#x2F;api&#x2F;usersにレート制限を実装（TODO.md item 3参照）&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;- APIドキュメントの更新（docs&#x2F;api-spec.md参照）&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;gitリポジトリ内では、
&lt;code&gt;git diff --name-only&lt;&#x2F;code&gt;と&lt;code&gt;git status&lt;&#x2F;code&gt;の
情報も自動的に取り込まれ、
変更ファイルの一覧が正確に記録されます。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;&#x2F;jrnl-restore_—_前回の続きから再開&quot;&gt;&lt;code&gt;&#x2F;jrnl-restore&lt;&#x2F;code&gt; — 前回の続きから再開&lt;&#x2F;h3&gt;
&lt;p&gt;翌朝、あるいは数日ぶりに
プロジェクトを開いたとき、
このコマンドで前回の状態を復元します。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&amp;gt; &#x2F;jrnl-restore&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Claude Codeは以下のステップで
動作します。&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;jrnlから最新のハンドオフを取得&lt;&#x2F;li&gt;
&lt;li&gt;ハンドオフに記載されたファイル
（TODO.md、ドキュメントなど）を
実際に読み込み&lt;&#x2F;li&gt;
&lt;li&gt;gitリポジトリなら、
ハンドオフ以降のコミットや
未コミットの変更も確認&lt;&#x2F;li&gt;
&lt;li&gt;これらを総合して「前回の続き」として
提示する。&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;ハンドオフが古くなっていても
問題ありません。
ハンドオフはあくまでスタート地点であり、
AIがプロジェクトファイルを読んで
最新の状態を把握します。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;&#x2F;jrnl-status_—_全プロジェクト横断ビュー&quot;&gt;&lt;code&gt;&#x2F;jrnl-status&lt;&#x2F;code&gt; — 全プロジェクト横断ビュー&lt;&#x2F;h3&gt;
&lt;p&gt;複数プロジェクトを並行している
開発者にとって、
これが最も価値のある
コマンドかもしれません。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&amp;gt; &#x2F;jrnl-status&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;過去7日間（デフォルト）のハンドオフから、
全プロジェクトの状況を一覧表示します。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Projects (last 7 days):&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;@api-server (2026-02-10)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  Status: 認証ミドルウェアのリファクタリング完了&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  Next: レート制限の実装&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;@mobile-app (2026-02-08)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  Status: プッシュ通知の統合完了&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  Next: iOSバッジ数のバグ修正&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;@docs-site (2026-02-06)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  Status: 新テーマへの移行がブロック中&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  Next: デザインチームのアセット待ち&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;月曜朝の計画や週次レビューで
威力を発揮します。
&lt;code&gt;&#x2F;jrnl-status 30&lt;&#x2F;code&gt;で
過去30日に拡張できます。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;&#x2F;jrnl-log_—_作業記録の自動生成&quot;&gt;&lt;code&gt;&#x2F;jrnl-log&lt;&#x2F;code&gt; — 作業記録の自動生成&lt;&#x2F;h3&gt;
&lt;p&gt;セッション中の作業を振り返って
記録します。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&amp;gt; &#x2F;jrnl-log&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Claude Codeがセッション内容を分析し、
作業ログを自動生成します。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Log: 認証バグ3件修正とOAuthテスト追加 @api-server @log&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Completed:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;- 認証バグ修正（issues #45, #47, #48）&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;- トークンリフレッシュに指数バックオフを導入&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;- OAuthフローの統合テスト追加&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Decisions:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;- リフレッシュトークンのTTLを24時間から72時間に変更&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;日報やスタンドアップの素材として、
あるいは個人の振り返りとして
活用できます。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;自然言語でも使える&quot;&gt;自然言語でも使える&lt;&#x2F;h2&gt;
&lt;p&gt;スラッシュコマンドだけでなく、
自然言語でもjrnlと対話できます。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&amp;gt; ジャーナルに追加して：決済APIはバリデーションエラーでも200を返す。&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  response.statusフィールドを確認する必要がある&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&amp;gt; 先週のジャーナルを見せて&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&amp;gt; 昨日何をしていた？&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&amp;gt; 認証に関するジャーナルエントリを検索して&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;jrnlのコマンド体系を知らなくても、
Claude Codeが適切なコマンドに変換して
実行します。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;タグによる情報の分類&quot;&gt;タグによる情報の分類&lt;&#x2F;h2&gt;
&lt;p&gt;jrnl-toolsは、
シンプルなタグ体系で情報を分類します。&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;タグ&lt;&#x2F;th&gt;&lt;th&gt;用途&lt;&#x2F;th&gt;&lt;th&gt;時間の向き&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;@&amp;lt;project&amp;gt;&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;プロジェクト識別（自動付与）&lt;&#x2F;td&gt;&lt;td&gt;-&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;@log&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;過去の記録（作業、調査、判断）&lt;&#x2F;td&gt;&lt;td&gt;過去&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;@handoff&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;次セッションへの引き継ぎ&lt;&#x2F;td&gt;&lt;td&gt;未来&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;@idea&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;いつか検討するアイデア&lt;&#x2F;td&gt;&lt;td&gt;不定&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;プロジェクトタグは&lt;code&gt;CLAUDE.md&lt;&#x2F;code&gt;に
設定しておくと、
自動的にすべてのエントリに付与されます。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;markdown&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;**&lt;&#x2F;span&gt;&lt;span class=&quot;z-markup z-bold&quot;&gt;jrnl Project Tag:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;**&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt; api-server&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;この仕組みにより、
&lt;code&gt;jrnl @api-server&lt;&#x2F;code&gt;で
特定プロジェクトのエントリだけを、
&lt;code&gt;jrnl @handoff&lt;&#x2F;code&gt;でプロジェクト横断の
ハンドオフだけを
フィルタリングできます。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;1日のワークフロー&quot;&gt;1日のワークフロー&lt;&#x2F;h2&gt;
&lt;p&gt;jrnl-toolsを使った
典型的な1日の流れを紹介します。&lt;&#x2F;p&gt;
&lt;p&gt;朝はまず状況を把握し、文脈を復元します。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;jrnl-status          # 全プロジェクトの状況を確認&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;jrnl-restore         # 今日のプロジェクトの前回状態を復元&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;作業中に気づいたことは、
その場で記録します。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&amp;gt; ジャーナルに追加：キャッシュのTTLを5分にすると&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  レスポンスタイムが40%改善した&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&amp;gt; このアイデアを保存：将来的にGraphQL Subscriptionsで&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  リアルタイム更新を実装すべき&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;夕方、作業を終える前に
引き継ぎと記録を残します。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;jrnl-handoff         # 明日のセッションへの引き継ぎ&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;jrnl-log             # 今日の作業記録（オプション）&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;この流れを習慣化すると、
セッション間の文脈断絶がほぼなくなります。
翌朝の「何やってたっけ？」が
「はい、昨日の続きですね」に変わります。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;セットアップ&quot;&gt;セットアップ&lt;&#x2F;h2&gt;
&lt;p&gt;事前に&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;jrnl.sh&#x2F;&quot;&gt;jrnl&lt;&#x2F;a&gt;の
インストールが必要です。
Claude Codeの&lt;code&gt;&#x2F;plugin&lt;&#x2F;code&gt;コマンドから
インストールします。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# マーケットプレイスを登録&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;&#x2F;plugin&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; marketplace add yostos&#x2F;claude-code-plugins&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# プラグインをインストール&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;&#x2F;plugin&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; install jrnl-tools@yostos-claude-code-plugins&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;各プロジェクトの&lt;code&gt;CLAUDE.md&lt;&#x2F;code&gt;に、
プロジェクトタグを追加します。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;markdown&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;**&lt;&#x2F;span&gt;&lt;span class=&quot;z-markup z-bold&quot;&gt;jrnl Project Tag:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;**&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt; myproject&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;これだけで準備完了です。
設定していなくても、
初回実行時にClaude Codeが
プロジェクト名を聞いてくれます。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;安全策と注意事項&quot;&gt;安全策と注意事項&lt;&#x2F;h2&gt;
&lt;p&gt;jrnl-toolsは「壊さない」ことを
重視して設計されています。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;削除操作なし&lt;&#x2F;strong&gt; —
エントリの削除は不可。
誤操作によるデータ消失を防止&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;暗号化操作なし&lt;&#x2F;strong&gt; —
パスワード処理のセキュリティリスクを
回避&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;追記のみ&lt;&#x2F;strong&gt; —
既存のエントリを変更しない。
編集が必要な場合は
&lt;code&gt;jrnl --edit&lt;&#x2F;code&gt;の使用をガイド&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;ただし、利用にあたって
認識しておくべき点があります。&lt;&#x2F;p&gt;
&lt;p&gt;機密情報の取り扱いには注意してください。
&lt;code&gt;&#x2F;jrnl-handoff&lt;&#x2F;code&gt;や&lt;code&gt;&#x2F;jrnl-log&lt;&#x2F;code&gt;は
セッション内容を要約して
jrnlに記録します。
セッション中にAPIキーや認証情報を
扱った場合、
それらが要約に含まれる可能性があります。
jrnlはデフォルトでプレーンテキスト
保存のため、
機密性の高いプロジェクトでは
&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;jrnl.sh&#x2F;en&#x2F;stable&#x2F;encryption&#x2F;&quot;&gt;jrnlの暗号化機能&lt;&#x2F;a&gt;の
利用を推奨します。&lt;&#x2F;p&gt;
&lt;p&gt;プロジェクト横断機能の情報分離にも
配慮が必要です。
&lt;code&gt;&#x2F;jrnl-status&lt;&#x2F;code&gt;は全プロジェクトの状況を
横断表示する便利な機能ですが、
裏を返せば異なるプロジェクトの情報が
同じジャーナルに混在することを
意味します。
異なる機密レベルのプロジェクトを
扱う場合は、この点を考慮してください。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;Auto_Memoryの登場_—_公式機能との棲み分け&quot;&gt;Auto Memoryの登場 — 公式機能との棲み分け&lt;&#x2F;h2&gt;
&lt;p&gt;ここまでjrnl-toolsの設計と使い方を
紹介してきました。
しかし、このプラグインを開発していた
2026年2月5日、状況が変わりました。
Claude Code v2.1.32のリリースで
Auto Memory&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-auto-memory-1&quot;&gt;&lt;a href=&quot;#fn-auto-memory&quot;&gt;2&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;という機能が
追加されたのです。&lt;&#x2F;p&gt;
&lt;p&gt;「ハンドオフして」とClaude Codeに
依頼するだけで、
次のセッションへの引き継ぎ情報が
&lt;code&gt;~&#x2F;.claude&#x2F;projects&#x2F;&lt;&#x2F;code&gt;配下の
メモリファイルに自動保存されます。
プロジェクトのパターンや設定も
自動的に記録され、
次回セッション開始時に
システムプロンプトへ読み込まれます。
セッション終了時に要点を
自動記録するSession
Memory&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-session-memory-1&quot;&gt;&lt;a href=&quot;#fn-session-memory&quot;&gt;3&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;も含め、
&lt;strong&gt;同じプロジェクト内での
セッション引き継ぎは
公式機能でカバーできるように
なりました。&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;正直に言えば、
開発中のプラグインと公式機能の
守備範囲が一部重なりました。
では、jrnl-toolsは
不要になったのでしょうか。&lt;&#x2F;p&gt;
&lt;p&gt;実際に使い比べてみると、
両者の性質は異なっていました。&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;特性&lt;&#x2F;th&gt;&lt;th&gt;Auto Memory&lt;&#x2F;th&gt;&lt;th&gt;jrnl-tools&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;情報の性質&lt;&#x2F;td&gt;&lt;td&gt;ストック（安定した知識）&lt;&#x2F;td&gt;&lt;td&gt;フロー（時系列の記録）&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;保存先&lt;&#x2F;td&gt;&lt;td&gt;プロジェクトごとのローカルファイル&lt;&#x2F;td&gt;&lt;td&gt;グローバルなjrnlジャーナル&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;スコープ&lt;&#x2F;td&gt;&lt;td&gt;単一プロジェクト&lt;&#x2F;td&gt;&lt;td&gt;クロスプロジェクト&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;次セッションへの引き継ぎ&lt;&#x2F;td&gt;&lt;td&gt;自動（システムプロンプトに読み込み）&lt;&#x2F;td&gt;&lt;td&gt;明示的（&lt;code&gt;&#x2F;jrnl-restore&lt;&#x2F;code&gt;で復元）&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;過去の作業履歴&lt;&#x2F;td&gt;&lt;td&gt;新しい知見で上書き（約200行の自動読み込み枠）&lt;&#x2F;td&gt;&lt;td&gt;日付付きで蓄積・検索可能&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Claude Code外からのアクセス&lt;&#x2F;td&gt;&lt;td&gt;想定されていない&lt;&#x2F;td&gt;&lt;td&gt;&lt;code&gt;jrnl&lt;&#x2F;code&gt;コマンドで直接参照可能&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;Auto Memoryは
**「プロジェクトの知識」**の
永続化に優れています。
コーディング規約、
プロジェクト構造、
ユーザーの好みといった安定した情報は、
Auto Memoryに任せるのが最適です。&lt;&#x2F;p&gt;
&lt;p&gt;一方、jrnl-toolsは
**「作業の記録」**に特化しています。
「いつ何をしたか」
「なぜその判断をしたか」という
時系列の文脈は、
Auto Memoryでは整理されて失われますが、
jrnlには蓄積されていきます。
&lt;code&gt;&#x2F;jrnl-status&lt;&#x2F;code&gt;による
プロジェクト横断ビューも、
プロジェクト単位で分離された
Auto Memoryでは実現できません。&lt;&#x2F;p&gt;
&lt;p&gt;両者は競合せず、補完関係にあります。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;まとめ&quot;&gt;まとめ&lt;&#x2F;h2&gt;
&lt;p&gt;jrnl-toolsは、
Claude Codeのセッションと
プロジェクトの壁を超えた
開発体験を実現するプラグインです。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;プロジェクト間の壁を超える&lt;&#x2F;strong&gt; →
jrnlをハブにした横断ビューで、
全プロジェクトの状況を一望&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;作業履歴を蓄積する&lt;&#x2F;strong&gt; →
時系列のログとして
検索・振り返りが可能&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Claude Codeの外からも
アクセスできる&lt;&#x2F;strong&gt; →
ターミナルから直接参照でき、
独立したツールとして機能&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Auto Memoryが「プロジェクトの知識」を、
jrnlが「作業の記録」を担う。
この棲み分けのもとで、
開発者のワークフローは
さらに改善されます。&lt;&#x2F;p&gt;
&lt;p&gt;jrnlのインストールとプラグインの導入は
数分で完了します。
まずは今日の作業を&lt;code&gt;&#x2F;jrnl-handoff&lt;&#x2F;code&gt;で
記録するところから始めてみてください。
使ってみた感想や改善のアイデアがあれば、
この記事のコメントや
GitHubリポジトリのIssueで
気軽にお聞かせください。&lt;&#x2F;p&gt;
&lt;section class=&quot;footnotes&quot;&gt;
&lt;ol class=&quot;footnotes-list&quot;&gt;
&lt;li id=&quot;fn-jrnl-mcp&quot;&gt;
&lt;p&gt;以前
&lt;a href=&quot;&#x2F;blog&#x2F;2025&#x2F;07&#x2F;first-mcp-server-development&#x2F;&quot;&gt;jrnl-mcp&lt;&#x2F;a&gt;
というMCPサーバーを作り、
Claude DesktopやClaude Codeから
jrnlを操作できるようにしていました。
Claude Codeのプラグインへ移植しようとした際、
MCPのツールAPIを経由しなくても
Claude Codeならjrnlコマンドを
直接実行できることに気づき、
必要なのはAPIではなく
ワークフローの設計だという
発想の転換がありました。 &lt;a href=&quot;#fr-jrnl-mcp-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li id=&quot;fn-auto-memory&quot;&gt;
&lt;p&gt;Auto Memoryは、
Claude Code v2.1.32
（2026年2月5日リリース）で
追加された機能です。
セッション中に発見した
プロジェクトのパターンや設定を
&lt;code&gt;~&#x2F;.claude&#x2F;projects&#x2F;&lt;&#x2F;code&gt;配下の
メモリファイルに自動保存し、
次回セッションのシステムプロンプトに
読み込みます。「ハンドオフして」と
依頼すれば
次にやるべきことも保存できます。
詳細は
&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;code.claude.com&#x2F;docs&#x2F;en&#x2F;memory&quot;&gt;公式ドキュメント&lt;&#x2F;a&gt;
を参照してください。 &lt;a href=&quot;#fr-auto-memory-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li id=&quot;fn-session-memory&quot;&gt;
&lt;p&gt;2026年2月現在の
Session Memoryは、
セッション終了時に会話の要点を
自動的に記録する機能です。
Claude Code（Pro&#x2F;Maxプラン、
Anthropic API経由）で利用でき、
同じプロジェクトの次回セッションで
参照できます。
ただしプロジェクトごとに分離されており、
異なるプロジェクト間での共有は
できません。
Bedrock・Vertex・Foundry経由の
利用ではフィーチャーフラグにより
&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;anthropics&#x2F;claude-code&#x2F;issues&#x2F;13706&quot;&gt;無効化されています&lt;&#x2F;a&gt;。 &lt;a href=&quot;#fr-session-memory-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;&#x2F;section&gt;
</content>
        <summary type="html">「昨日の続きをお願い」が通じない。
セッションごとに記憶が消える
Claude Codeの弱点を、
CLIジャーナルツールjrnlで補う
プラグインを開発しました。
プロジェクト横断の状況把握から
Auto Memoryとの使い分けまで
解説します。
</summary>
        </entry><entry xml:lang="en">
        <title>ZolaブログにOGP画像自動生成を組み込んだ</title>
        <published>2026-02-10T00:00:00+00:00</published>
        <updated>2026-02-10T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2026/02/ogp-image-generation/" type="text/html"/>
        <id>https://codedchords.dev/blog/2026/02/ogp-image-generation/</id>
        
            <content type="html">&lt;p&gt;このブログは&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.getzola.org&#x2F;&quot;&gt;Zola&lt;&#x2F;a&gt;と&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;welpo&#x2F;tabi&quot;&gt;tabi&lt;&#x2F;a&gt;テーマで運用しています。
&lt;a href=&quot;https:&#x2F;&#x2F;codedchords.dev&#x2F;blog&#x2F;2026&#x2F;01&#x2F;blog-to-zola-aws-cleanup&#x2F;&quot;&gt;Next.jsから移行して&lt;&#x2F;a&gt;10日ほど経ち、
基本的な運用は安定してきましたが、
OGP画像が未対応のままでした。
SNSでリンクを共有したときに
表示される画像がないのは寂しいものです。
対応の顛末を記録します。&lt;&#x2F;p&gt;
&lt;span id=&quot;continue-reading&quot;&gt;&lt;&#x2F;span&gt;&lt;h2 id=&quot;OGP画像がなぜ必要か&quot;&gt;OGP画像がなぜ必要か&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;ogp.me&#x2F;&quot;&gt;OGP（Open Graph Protocol）&lt;&#x2F;a&gt;は、
URLを共有した際にタイトルや説明文、
画像をプレビュー表示するための仕組みです。
BlueskyやSlack、LINEなど、
いまやほとんどのサービスが対応しています。&lt;&#x2F;p&gt;
&lt;p&gt;OGP画像が未設定の場合、
リンクはテキストだけの素っ気ない表示になるか、
サイト共通のデフォルト画像が使われます。
このブログでは後者の状態でした。
どの記事を共有しても同じ画像が出るので、
タイムラインで見かけても
何の記事か判別できません。&lt;&#x2F;p&gt;
&lt;!-- textlint-disable --&gt;
&lt;img
  src=&quot;https:&amp;#x2F;&amp;#x2F;codedchords.dev&amp;#x2F;blog&amp;#x2F;2026&amp;#x2F;02&amp;#x2F;ogp-image-generation&amp;#x2F;before.webp?h=31ab83f0940f69a0288b&quot;
  alt=&quot;対応前：すべての記事で同じ画像&quot; width=&quot;531&quot; height=&quot;377&quot; loading=&quot;lazy&quot;
&#x2F;&gt;&lt;!-- textlint-enable --&gt;
&lt;p&gt;記事ごとにタイトル入りの画像を用意すれば、
共有リンクだけで内容が伝わります。&lt;&#x2F;p&gt;
&lt;!-- textlint-disable --&gt;
&lt;img
  src=&quot;https:&amp;#x2F;&amp;#x2F;codedchords.dev&amp;#x2F;blog&amp;#x2F;2026&amp;#x2F;02&amp;#x2F;ogp-image-generation&amp;#x2F;after.webp?h=61caf7e3efb4f885ee01&quot;
  alt=&quot;対応後：記事タイトル入りのOGP画像&quot; width=&quot;522&quot; height=&quot;392&quot; loading=&quot;lazy&quot;
&#x2F;&gt;&lt;!-- textlint-enable --&gt;
&lt;h2 id=&quot;Zola_+_tabiテーマでのOGP画像の扱い&quot;&gt;Zola + tabiテーマでのOGP画像の扱い&lt;&#x2F;h2&gt;
&lt;p&gt;Zolaの画像処理機能は &lt;code&gt;resize_image()&lt;&#x2F;code&gt; による
リサイズ、クロップ、フォーマット変換に
限られます。
テキストを画像に描画する機能はなく、
OGP画像の自動生成は備わっていません。&lt;&#x2F;p&gt;
&lt;p&gt;tabiテーマ側には
&lt;code&gt;social_media_images.html&lt;&#x2F;code&gt; という
テンプレートがあり、frontmatterの
&lt;code&gt;[extra] social_media_card&lt;&#x2F;code&gt; で
指定された画像パスから &lt;code&gt;og:image&lt;&#x2F;code&gt; 等の
メタタグを出力します。
ただし画像ファイルへの参照を担うだけで、
画像そのものは生成しません。
ファイルは事前に用意しておく必要があります。&lt;&#x2F;p&gt;
&lt;p&gt;tabiの作者であるwelpo氏も、
自身のブログ
（&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;osc.garden&#x2F;blog&#x2F;automating-social-media-cards-zola&#x2F;&quot;&gt;osc.garden&lt;&#x2F;a&gt;）
でこの課題に取り組んでいます。
氏のアプローチは &lt;code&gt;shot-scraper&lt;&#x2F;code&gt; で
ページのスクリーンショットを撮影し、
OGP画像にするというものです。
ページの見た目がそのまま
プレビューになるため、
デザインの一貫性は高いです。
一方で、Zolaの開発サーバーを起動した上で
スクリーンショットを撮る必要があり、
ビルドプロセスが複雑になります。&lt;&#x2F;p&gt;
&lt;p&gt;このブログでも独自の対応が必要でした。
スクリーンショット方式はビルドの複雑さから
見送り、別のアプローチを探ることにしました。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;選んだアプローチ&quot;&gt;選んだアプローチ&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;OGP画像生成方式&quot;&gt;OGP画像生成方式&lt;&#x2F;h3&gt;
&lt;p&gt;OGP画像の生成方式には、大きく2つの方向があります。&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Zenn.devのような固定フレーム画像に記事タイトルを合成する方式&lt;&#x2F;li&gt;
&lt;li&gt;各記事のカバー画像に記事タイトルを合成する方式&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;フレーム方式はすべての記事で統一感が出ますが、
記事ごとの個性は薄くなります。
カバー画像方式は記事の内容が視覚的に伝わる
反面、画像のない記事には対応できません。&lt;&#x2F;p&gt;
&lt;p&gt;このブログには既存記事が200近くあり、
写真やスクリーンショットを含む記事と、
テキストだけの記事が混在しています。
どちらか一方の方式では、
必ずカバーできない記事が出てきます。&lt;&#x2F;p&gt;
&lt;p&gt;そこで両者のハイブリッド方式を採りました。
記事フォルダにOGPの背景として十分なサイズの
画像があればそれを使い、
なければサイト共通のデフォルト画像を使い、記事タイトルを合成する&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;yostos&#x2F;blog-yostos&#x2F;blob&#x2F;main&#x2F;scripts&#x2F;generate-ogp.mjs&quot;&gt;一括生成スクリプト&lt;&#x2F;a&gt;を作成しました。
カバー画像のある記事は記事固有の見た目になり、
画像がない記事もブログとしての統一感を保てます。
どの記事に画像があるかを人が判断する必要もなく、
スクリプトがサイズを見て自動で振り分けます。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;OGP画像配置戦略&quot;&gt;OGP画像配置戦略&lt;&#x2F;h3&gt;
&lt;p&gt;Zolaでは記事と同じフォルダに画像を
配置できます。
そこで、OGP画像は &lt;code&gt;ogp.webp&lt;&#x2F;code&gt; という固定のファイル名で
記事フォルダに出力することとしました。&lt;&#x2F;p&gt;
&lt;p&gt;こうすることで、各記事のfrontmatterからは常に同じ相対パスでOGP画像を参照できます。&lt;&#x2F;p&gt;
&lt;p&gt;既存記事については、同じfrontmatterを追加するだけで対応できます。
frontmatterに機械的に &lt;code&gt;social_media_card = &quot;ogp.webp&quot;&lt;&#x2F;code&gt; を
追加する&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;yostos&#x2F;blog-yostos&#x2F;blob&#x2F;main&#x2F;scripts&#x2F;add-ogp-frontmatter.mjs&quot;&gt;スクリプト&lt;&#x2F;a&gt;を作成して一括で対応しました。&lt;&#x2F;p&gt;
&lt;p&gt;新規記事についてはNeovimのテンプレート機能で
frontmatterに &lt;code&gt;social_media_card = &quot;ogp.webp&quot;&lt;&#x2F;code&gt;
を最初から埋め込んでおくことで対応できてしまいます。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;運用について&quot;&gt;運用について&lt;&#x2F;h3&gt;
&lt;p&gt;今後の運用でも、今回作成した&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;yostos&#x2F;blog-yostos&#x2F;blob&#x2F;main&#x2F;scripts&#x2F;generate-ogp.mjs&quot;&gt;一括生成スクリプト&lt;&#x2F;a&gt;を活用します。&lt;&#x2F;p&gt;
&lt;p&gt;このスクリプトは、既にOGP画像がある記事はスキップするため、
新しい記事を書いたらこのスクリプトを実行するだけで新規記事の分だけOGP画像を生成してくれます。
そして記事のテンプレートにもうすでにOGP画像の指定がfrontmatterとして設定されています。&lt;&#x2F;p&gt;
&lt;p&gt;もちろん、今後ベースとなったフレーム画像が気にくわなければ各記事フォルダの&lt;code&gt;ogp.webp&lt;&#x2F;code&gt;を削除すれば再作成されます。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;導入してみて&quot;&gt;導入してみて&lt;&#x2F;h2&gt;
&lt;p&gt;200記事すべてにOGP画像が生成され、
SNS共有時の見栄えが改善されました。&lt;&#x2F;p&gt;
&lt;p&gt;今回は過度に自動化せず、
新規記事については毎回手動で
OGP画像生成スクリプトを実行する
運用にしています。
&lt;code&gt;zola serve&lt;&#x2F;code&gt; でプレビューを確認する際、
OGP画像がないとエラーになるのが
微妙にストレスなので、
いずれビルドプロセスへの組み込みも
検討したいところです。&lt;&#x2F;p&gt;
&lt;!-- textlint-disable --&gt;
&lt;div class=&quot;admonition info&quot;&gt;
    &lt;div class=&quot;admonition-icon admonition-icon-info&quot;&gt;&lt;&#x2F;div&gt;
    &lt;div class=&quot;admonition-content&quot;&gt;
        &lt;strong class=&quot;admonition-title&quot;&gt;関連記事&lt;&#x2F;strong&gt;
        &lt;p&gt;実装の技術的な詳細は
Zennに投稿しています。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;zenn.dev&#x2F;yostos&#x2F;articles&#x2F;zola-ogp-auto-generation&quot;&gt;Zola + tabiテーマでOGP画像を自動生成する
（Zenn）&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;

    &lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;!-- textlint-enable --&gt;
</content>
        <summary type="html">静的サイトジェネレーターZolaとtabiテーマの組み合わせで
運用しているこのブログに、OGP画像の自動生成を導入しました。
Zolaに組み込みの仕組みがない中でどう対応したか、
検討から導入までの経緯を記録します。
</summary>
        </entry><entry xml:lang="en">
        <title>生成AI時代、重力に魂を引かれるな</title>
        <published>2026-02-09T12:30:00+09:00</published>
        <updated>2026-02-09T12:30:00+09:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2026/02/ai-human-divergence/" type="text/html"/>
        <id>https://codedchords.dev/blog/2026/02/ai-human-divergence/</id>
        
            <content type="html">&lt;!-- textlint-disable --&gt;
&lt;img
  src=&quot;https:&amp;#x2F;&amp;#x2F;codedchords.dev&amp;#x2F;blog&amp;#x2F;2026&amp;#x2F;02&amp;#x2F;ai-human-divergence&amp;#x2F;cover.webp?h=47e368ab0f46eda916c2&quot;
  alt=&quot;Cover&quot; width=&quot;1800&quot; height=&quot;1009&quot; loading=&quot;lazy&quot;
&#x2F;&gt;&lt;!-- textlint-enable --&gt;
&lt;h2 id=&quot;はじめに&quot;&gt;はじめに&lt;&#x2F;h2&gt;
&lt;p&gt;革新的な技術が目の前にあり、誰でも試せる状況になったとき、
実際に試す人はどれくらいいるでしょうか。&lt;&#x2F;p&gt;
&lt;p&gt;この1年、生成AI、Markdown、テキストエディタの活用など生産性の
上げるための多くのものを紹介しても、何ひとつ試そうともしない人を目の当たりにしてきました。&lt;&#x2F;p&gt;
&lt;p&gt;この1年に限らずこれまでの私の観測では、どの現場でも新技術を2割が試し、4割は「いつか試そう」と思いながら試さず、
残りの4割は試そうともしません。
これは&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;amzn.to&#x2F;3Zp2HiL&quot;&gt;Everett Rogersのイノベーション普及理論&lt;&#x2F;a&gt; &lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-1-1&quot;&gt;&lt;a href=&quot;#fn-1&quot;&gt;1&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;とも一致します。&lt;&#x2F;p&gt;
&lt;p&gt;興味深いのは、この比率が技術の難易度とほぼ無関係なことです。
生成AIのような革新的技術だけでなく、Markdownのような
学習コスト30分、チートシート1枚で済むツールでも同じだということです。&lt;&#x2F;p&gt;
&lt;p&gt;これはもはや能力の問題ではありません。
新しいことを取り入れる意志の問題です。
腰が重い、というより、重力に魂を引かれているのかもしれません。&lt;&#x2F;p&gt;
&lt;p&gt;そしてこの2割と8割の差は、生成AIの時代において
&lt;strong&gt;決定的な分断&lt;&#x2F;strong&gt;へと発展しようとしています。
以降、この2割を「先行者」、8割を「追随者」と呼ぶことにします。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;2つの革新&quot;&gt;2つの革新&lt;&#x2F;h2&gt;
&lt;p&gt;生成AIも同様です。
本格的に活用し、自身の生活や業務へ取り入れているのは2割程度でしょう。&lt;&#x2F;p&gt;
&lt;p&gt;従来の技術革新と今回の「生成AI」が決定的に異なるのは、
もたらす変化が大きく2つに分けられることです。&lt;&#x2F;p&gt;
&lt;p&gt;1つ目は「&lt;strong&gt;実行力の民主化&lt;&#x2F;strong&gt;」です。
思考から実行し実現するまでの摩擦がほぼゼロになりました。
アイデアさえあれば、コード、文章、分析、デザイン、
それを形にするまでの障壁がなくなりつつあります。&lt;&#x2F;p&gt;
&lt;p&gt;2つ目は「&lt;strong&gt;認知の拡張&lt;&#x2F;strong&gt;」です。
自分一人の脳では到達できない思考の深さと広さを得られるようになりました。
これは生成AIの認知力が高いということではありません。
生成AIを壁打ち相手、批判者、専門家、編集者として常に隣に置くことで、
自身の物事の捉え方や解決への発想、新たな着想力が
これまでとは比べ物にならないくらい速く柔軟に拡がります。
そう感じた方は多いはずです。
これは単なるツールではなく、認知そのものの拡張です。&lt;&#x2F;p&gt;
&lt;p&gt;先行者と追随者の間の前者のギャップは時間が解決します。
生成AIがさまざまなツールに組み込まれれば、
追随者もそのメリットを享受できるようになるでしょう。
Gmailの文章補完、Excelの自動分析、Canvaのデザイン提案。
これらは「使う」意志がなくても、自然に恩恵を受けられます。&lt;&#x2F;p&gt;
&lt;p&gt;問題は後者です。認知の拡張は、能動的に求めなければ得られません。
そして、いち早く生成AIを活用している先行者は、
今この瞬間も認知を拡張し続けています。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;AI時代の分断&quot;&gt;AI時代の分断&lt;&#x2F;h2&gt;
&lt;p&gt;ここで&lt;strong&gt;決定的な分岐&lt;&#x2F;strong&gt;が生まれます。&lt;&#x2F;p&gt;
&lt;p&gt;追随者はメーカーがAIで便利にした製品を使います。
便利にはなります。
しかし、製品が想定した範囲内でしか動けません。
誰かが設計した体験の中にいます。&lt;&#x2F;p&gt;
&lt;p&gt;先行者はAIそのものを使います。
そして時代はエージェント型AI、
現実世界の道具を使えるAIの時代になりました。
何をさせるか、どう組み合わせるかをAIに指示し、
道具に縛られずAIで生産性を上げ、
さらに認知力の拡張を続けることができます。&lt;&#x2F;p&gt;
&lt;p&gt;前者は消費者、後者は設計者です。&lt;&#x2F;p&gt;
&lt;p&gt;エンジニアの世界では、既にこの分断が始まっています。&lt;&#x2F;p&gt;
&lt;p&gt;昨年まではGitHub Copilotのように
エディタやIDEにAIを組み込んだものがもてはやされてきました。
しかしClaude Codeの登場で状況が変わりました。
エディタに組み込まれていなくても、
Claude Code自身がツールを操り開発を進められるようになったのです。
エンジニアは自身のコーディングの支援だけでなく、
テスト、設計、要件定義、構想策定まで
Claude Codeと協業しながら生成AIの適用範囲を広げていけます。
単純な作業を任せるだけでなく、
これまで実現コストで躊躇していた新しいアイデアへ
どんどん挑戦できるようになりました。&lt;&#x2F;p&gt;
&lt;p&gt;非エンジニアの世界でも同じことが起きようとしています。
これまではExcelやWordにAIが組み込まれるのを歓迎していました。
しかしClaude Coworkが普及すれば、そんなことは関係なくなります。
好きなツールをCoworkから使いこなして業務ができるようになります。
事実、Claude Coworkの発表後、SaaSプロバイダーの株価は軒並み暴落しました。
市場はこの変化の意味を理解しています。&lt;&#x2F;p&gt;
&lt;p&gt;設計者になるか、消費者のままでいるか。その選択が迫られています。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;量から質への転化&quot;&gt;量から質への転化&lt;&#x2F;h2&gt;
&lt;p&gt;もう1つ、見過ごせない力学があります。
「量をこなせば、質が向上する」という量質変換&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-2-1&quot;&gt;&lt;a href=&quot;#fn-2&quot;&gt;2&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;があります。
ここで重要なのは、生成AIというツールの使いこなしではなく、
&lt;strong&gt;認知の拡張それ自体に量質変換が起きる&lt;&#x2F;strong&gt;ということです。&lt;&#x2F;p&gt;
&lt;p&gt;先行者は、生成AIと対話を重ねるたびに、
自分一人では到達できなかった思考領域に踏み込んでいます。
新しい視点を得れば、それを足がかりにさらに深い問いが立てられます。
深い問いに向き合えば、さらに広い視野が開けます。&lt;&#x2F;p&gt;
&lt;p&gt;これは単なるツールの習熟ではありません。
認知の拡張が認知の拡張を呼ぶ、爆発的な正のフィードバックです。&lt;&#x2F;p&gt;
&lt;p&gt;一度この拡張を経験すると、思考の出発点そのものが変わります。
昨日の自分には見えなかった問いが見えるようになり、
先月の自分には発想できなかった解決策が浮かぶようになります。
認知が広がれば、発想の幅も加速度的に広がります。
これが毎日、毎週、積み重なっていきます。&lt;&#x2F;p&gt;
&lt;p&gt;一方、追随者は最初の一歩を踏み出していません。
認知の拡張がなければ、量質変換も起きません。
差は線形ではなく、指数関数的に開いていきます。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;認知様式の分断&quot;&gt;認知様式の分断&lt;&#x2F;h2&gt;
&lt;p&gt;さらに深刻なのは、先行者と追随者の間で
コミュニケーションそのものが困難になっていくことです。&lt;&#x2F;p&gt;
&lt;p&gt;認知が拡張された者同士は、同じ地平に立って議論できます。
問題の捉え方、解決策の発想、思考の前提が揃っているからです。
言葉を尽くさなくても、互いの思考の輪郭が見えます。&lt;&#x2F;p&gt;
&lt;p&gt;一方、追随者との間では、まず見えている世界が違います。
先行者にとって当たり前の発想が、追随者には飛躍に見えます。
説明しようとしても、その説明を理解するための前提が共有されていません。&lt;&#x2F;p&gt;
&lt;p&gt;これは専門用語の問題ではありません。
認知の枠組みそのものが異なっているのです。&lt;&#x2F;p&gt;
&lt;p&gt;私たちは今、そうした分岐の入り口に立っているのかもしれません。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;私たちはどこへ向かうのか&quot;&gt;私たちはどこへ向かうのか&lt;&#x2F;h2&gt;
&lt;p&gt;先行者の認知は、日々拡張し続けています。
見える世界が広がり、立てられる問いが深まり、
発想の幅が際限なく広がっていきます。&lt;&#x2F;p&gt;
&lt;p&gt;追随者は、その変化に気づいていません。
気づかないまま、同じ枠組みの中で思考し続けます。
1年後、2年後、認知の差はどこまで開くでしょうか。&lt;&#x2F;p&gt;
&lt;p&gt;追随者が「置いていかれる」というより、
自ら「留まることを選んでいる」という方が正確かもしれません。
それが意識的な選択かどうかは問いません。&lt;&#x2F;p&gt;
&lt;p&gt;私たちは今、認知が分岐していく入り口に立っています。&lt;&#x2F;p&gt;
&lt;p&gt;あなたはどちら側にいますか。
そして、そこにいることを選んでいますか。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;まとめ&quot;&gt;まとめ&lt;&#x2F;h2&gt;
&lt;p&gt;私たちの世代だと、これはどこかで見た構図です。&lt;&#x2F;p&gt;
&lt;p&gt;1979年のテレビアニメ『機動戦士ガンダム』では、
人類の宇宙進出という革新への適応として「ニュータイプ&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-3-1&quot;&gt;&lt;a href=&quot;#fn-3&quot;&gt;3&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;」が生まれ、
「重力に魂を引かれた」オールドタイプとの分断が描かれていました。
現代における重力とは、慣れ親しんだツールや思考様式への執着かもしれません。
しかし、最終回では特殊なモビルスーツのパイロットである主人公のみならず同じ部隊のクルーが覚醒していく様が描かれています。&lt;&#x2F;p&gt;
&lt;p&gt;現代の革新についても、現状は追随者の側にいるとしてもそれは能力の問題ではありません。&lt;&#x2F;p&gt;
&lt;p&gt;先行者への最初の一歩は難しくありません。
Markdownを30分勉強し、Claude Proを使い始めましょう。&lt;&#x2F;p&gt;
&lt;p&gt;答えを求めるのではなく、壁打ち相手として問いを投げてみる。
それだけで、認知の拡張は動き始めます。&lt;&#x2F;p&gt;
&lt;!-- textlint-disable --&gt;
&lt;div class=&quot;admonition note&quot;&gt;
    &lt;div class=&quot;admonition-icon admonition-icon-note&quot;&gt;&lt;&#x2F;div&gt;
    &lt;div class=&quot;admonition-content&quot;&gt;
        &lt;strong class=&quot;admonition-title&quot;&gt;なぜClaudeなのか&lt;&#x2F;strong&gt;
        &lt;p&gt;私がClaudeを例に挙げているのは、2026年2月時点で
非エンジニア向けのエージェント機能（Cowork）を
提供しているのがAnthropicだけだからです。
認知の拡張を始めるなら、ChatGPTでもGeminiでも構いません。&lt;&#x2F;p&gt;

    &lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;!-- textlint-enable --&gt;
&lt;section class=&quot;footnotes&quot;&gt;
&lt;ol class=&quot;footnotes-list&quot;&gt;
&lt;li id=&quot;fn-1&quot;&gt;
&lt;p&gt;イノベーション普及理論は、新しい技術やサービスが市場に広がる過程を、消費者の採用タイミングに基づいて5つのタイプに分類し分析するマーケティング理論。1962年に提唱された。 5つのタイプとは、(1).イノベーター (革新者：2.5%)：最先端技術を好み、新しいものを進んで採用する。(2).アーリーアダプター (初期採用者：13.5%)：流行に敏感で、周囲に影響を与えるオピニオンリーダー。(3).アーリーマジョリティ (前期追随者：34%)：慎重派だが、新しいものを平均より早く採用する。
(4).レイトマジョリティ (後期追随者：34%)：懐疑的で、周囲の大半が使用して初めて採用する。(5).ラガード (遅滞層：16%)：最も保守的で、流行に関心が薄い。 &lt;a href=&quot;#fr-1-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li id=&quot;fn-2&quot;&gt;
&lt;p&gt;量質転化の法則。ヘーゲルの『小論理学』に由来する概念で、現代では一定の量を積み重ねることで臨界点に達し、能力や理解が劇的に向上するという原則として広く語られている。 &lt;a href=&quot;#fr-2-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li id=&quot;fn-3&quot;&gt;
&lt;p&gt;広大な宇宙空間への適合の結果、ニュータイプは空間を超えた非言語的コミュニケーション能力、超人的な感覚力と直感力、観察力と洞察力を持つ新しい人類として描かれています。 &lt;a href=&quot;#fr-3-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;&#x2F;section&gt;
</content>
        <summary type="html">生成AIは人類の分岐点となる革新です。
しかし8割の人は新しいものを試そうとしません。
慣れ親しんだやり方に留まり、一歩を踏み出せない。
それはまさに「重力に魂を引かれた」状態ではないでしょうか。
</summary>
        </entry><entry xml:lang="en">
        <title>なぜ塩漬けシステムからの脱却は「無理ゲー」になるのか</title>
        <published>2026-02-05T00:00:00+00:00</published>
        <updated>2026-02-05T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2026/02/why-stagnant-system-migration-fails/" type="text/html"/>
        <id>https://codedchords.dev/blog/2026/02/why-stagnant-system-migration-fails/</id>
        
            <content type="html">&lt;!-- textlint-disable --&gt;
&lt;div class=&quot;admonition note&quot;&gt;
    &lt;div class=&quot;admonition-icon admonition-icon-note&quot;&gt;&lt;&#x2F;div&gt;
    &lt;div class=&quot;admonition-content&quot;&gt;
        &lt;strong class=&quot;admonition-title&quot;&gt;NOTE&lt;&#x2F;strong&gt;
        &lt;p&gt;この記事は
&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;zenn.dev&#x2F;yostos&#x2F;articles&#x2F;why-stagnant-system-migration-fails&quot;&gt;Zenn.dev&lt;&#x2F;a&gt;
に掲載した記事の転載です。
本記事は特定の組織や個人を指すものではありません。&lt;&#x2F;p&gt;

    &lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;!-- textlint-enable --&gt;
&lt;details&gt;
&lt;summary&gt;Table of Contents&lt;&#x2F;summary&gt;
&lt;!-- toc --&gt;
&lt;&#x2F;details&gt;
&lt;h2 id=&quot;TL;DR&quot;&gt;TL;DR&lt;&#x2F;h2&gt;
&lt;p&gt;中小企業や自治体などIT部門が弱い組織では、10年、20年と塩漬けになった
システムからの脱却が「無理ゲー」に陥りやすい傾向があります。
ブラックボックス化・ベンダーロックイン・組織能力不足という問題が
互いに絡み合い、負のスパイラルを形成するからです。&lt;&#x2F;p&gt;
&lt;p&gt;根本原因は技術ではなく、組織的なITガバナンスの喪失にあります。
この状況からの脱出には膨大な投資と経営層の強いコミットメントが必要ですが、
そもそもこの状況に陥らないための予防が最善策です。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;はじめに&quot;&gt;はじめに&lt;&#x2F;h2&gt;
&lt;p&gt;IT部門を持たず塩漬けになったシステムで悩む組織では、
保守の手間がかからないSaaSへの移行を検討することが多いでしょう。
しかし、SaaSであれ新規開発であれ、長年運用してきた塩漬けシステムからの刷新は、
想像以上に困難を極めます。&lt;&#x2F;p&gt;
&lt;p&gt;ITプロジェクトの失敗率は決して低くありません。
Standish GroupのCHAOS Report 2020によれば、
ITプロジェクトの約70%が当初の目標を達成できないとされています。
特に、知見をもった要員が途絶えドキュメンテーションも十分でない
システムからの移行は、その中でも最も困難なカテゴリに属します。&lt;&#x2F;p&gt;
&lt;p&gt;本記事では、筆者が見聞した複数の事例をもとに、
システム刷新が「無理ゲー」と化す構造的な問題を解説します。
これは特殊な例ではなく、多くの組織が陥りがちな普遍的なパターンです。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;前提：この記事が想定する組織像&quot;&gt;前提：この記事が想定する組織像&lt;&#x2F;h2&gt;
&lt;p&gt;本記事で分析する「システム刷新が困難な組織」には、以下のような特徴があります。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;CIOが不在で、組織的なIT統制がない&lt;&#x2F;li&gt;
&lt;li&gt;専任のIT部門が存在しない、または機能していない&lt;&#x2F;li&gt;
&lt;li&gt;システム開発・保守を長年同じベンダーに依存してきた&lt;&#x2F;li&gt;
&lt;li&gt;仕様書・設計書が最新化されておらず、組織内で管理できていない&lt;&#x2F;li&gt;
&lt;li&gt;ソースコードの所在や最新版の把握ができていない&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;このような状態は、中小企業や地方自治体、非IT企業の事業部門などで珍しくありません。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;1._システムの完全なブラックボックス化&quot;&gt;1. システムの完全なブラックボックス化&lt;&#x2F;h2&gt;
&lt;p&gt;長年の運用の中で、システムは以下のような状態に陥っています。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;仕様書・設計書が存在しない、または最新でない&lt;&#x2F;li&gt;
&lt;li&gt;現在のシステムが何をしているのか誰も把握していない&lt;&#x2F;li&gt;
&lt;li&gt;信頼できるのはソースコードのみだが、組織では管理していない&lt;&#x2F;li&gt;
&lt;li&gt;ソースコードの可読性が低く、設計意図の理解が困難&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;さらに深刻なのは、文書化されていない知識の存在です。
暗黙知化した業務ルールが大量のコード内へ埋め込まれており、
誰も覚えていない例外処理が実は重要な機能だったりします。
文書化されていない仕様変更の積み重ねが、現在の動作を形成しています。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;2._ベンダーロックインの完成形&quot;&gt;2. ベンダーロックインの完成形&lt;&#x2F;h2&gt;
&lt;p&gt;このような状況では、ベンダーとの力関係が完全に逆転します。
ベンダーだけがシステムの知識を持っており、組織側には検証手段がなく、
ベンダーの言い値を受け入れるしかありません。
ベンダー自身も変更時の検証で対応しているだけで、完全な仕様把握は疑問です。
これは典型的なベンダーロックインの完成形です。&lt;&#x2F;p&gt;
&lt;p&gt;現行ベンダーに移行支援を依頼することも、構造的に困難です。
唯一システムのナレッジを持っている彼らは、
現行システムの保守で継続的な収益を得ています。
システム刷新が現行ベンダー以外へのSaaS移行などの場合、
積極的に協力するインセンティブがなく、
むしろ移行は現状のビジネス機会の損失を意味します。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;3._システム刷新に必要な組織能力&quot;&gt;3. システム刷新に必要な組織能力&lt;&#x2F;h2&gt;
&lt;p&gt;システム刷新を成功させるには、現行システムの分析と要件定義、
業務プロセスの文書化が必要です。
また多くの場合そのような組織ではSaaS製品を検討するでしょう。
SaaSを選択したとしても、SaaS製品の選定とギャップ分析、
業務プロセス改革の設計と実行、データ移行、段階的な移行と検証、
運用体制の確立といったステップが必要です。&lt;&#x2F;p&gt;
&lt;p&gt;これらを遂行するには、以下の能力が不可欠です。
名のある大企業でも全て満たしていることは稀です。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;現行システムの仕様を理解し文書化する能力&lt;&#x2F;li&gt;
&lt;li&gt;業務要件を定義し、システム要件に落とし込む能力&lt;&#x2F;li&gt;
&lt;li&gt;プロジェクト全体を管理する能力&lt;&#x2F;li&gt;
&lt;li&gt;SaaSやERPを移行先とする場合は、
その製品が前提とする業務プロセスを理解するナレッジ&lt;&#x2F;li&gt;
&lt;li&gt;業務改革やプロセスリエンジニアリングを推進する能力&lt;&#x2F;li&gt;
&lt;li&gt;経営層の高いコミットメントとリーダーシップ&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;4._3つの致命的なギャップ&quot;&gt;4. 3つの致命的なギャップ&lt;&#x2F;h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;移行の「正解」が誰にも分からない&lt;&#x2F;strong&gt; —
仕様書が古いため、現在のシステムがどう動いているか不明である。
つまり「移行後に何が実現されていればOKなのか」という基準が存在しない。&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;投資を正当化できない&lt;&#x2F;strong&gt; —
移行には膨大な投資が必要だが、
現状維持のためだけでは経営層の投資判断を得られない。
明確なビジネス成果や価値を経営層がコミットできなければ、
必要な予算確保は不可能である。&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;組織風土の問題&lt;&#x2F;strong&gt; —
能力不足だけでなく、組織文化にも課題がある。
経営層が成果をコミットするリーダーシップがなく、
トップダウンでの業務改革の経験もない。
大きな変革を受け入れる風土が醸成されておらず、
現場の抵抗を乗り越えて改革を推進する仕組みもない。
データや機能を諦めるような大胆な意思決定ができない。&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;h2 id=&quot;5._負のスパイラル&quot;&gt;5. 負のスパイラル&lt;&#x2F;h2&gt;
&lt;p&gt;塩漬け状態から脱却しようとSaaS移行を決意しても、
これらの問題が互いに絡み合い、負のスパイラルを形成します。&lt;&#x2F;p&gt;
&lt;!-- textlint-disable --&gt;


&lt;noscript&gt;
    &lt;strong&gt;⚠️ JavaScript is required to render the diagram.&lt;&#x2F;strong&gt;
&lt;&#x2F;noscript&gt;
&lt;pre class=&quot;mermaid invertible-image&quot;&gt;
    flowchart TD
A[仕様が不明] --&gt; B[要件を洗い出せない]
B --&gt; C[ベンダーは利益相反]
C --&gt; D[SaaS要件を定義できない]
D --&gt; E[SaaSを選定できない]
E --&gt; F[業務プロセス知識がない]
F --&gt; G[改革の経験・風土がない]
G --&gt; H[意思決定ができない]
H --&gt; I[移行失敗]
I -.-&gt; A
&lt;&#x2F;pre&gt;
&lt;!-- textlint-enable --&gt;
&lt;p&gt;では新規ベンダーに依頼すればよいのでしょうか。残念ながら、それも困難です。
現行システムの仕様不明により要件定義ができず、
リバースエンジニアリングには膨大なコストがかかります。
組織側に要件定義能力がなくプロジェクトは進まず、
責任範囲も不明確でリスクを引き受けられません。
優れたSIerやコンサル会社ほど、このような案件を忌避します。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;6._無理に進めた場合の予想シナリオ&quot;&gt;6. 無理に進めた場合の予想シナリオ&lt;&#x2F;h2&gt;
&lt;p&gt;仮に予算化されて、無理やりSaaS移行プロジェクトが開始されたとします。
典型的な失敗パターンは以下の通りです。&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th style=&quot;text-align: left&quot;&gt;フェーズ&lt;&#x2F;th&gt;&lt;th style=&quot;text-align: left&quot;&gt;時期&lt;&#x2F;th&gt;&lt;th style=&quot;text-align: left&quot;&gt;起こること&lt;&#x2F;th&gt;&lt;th style=&quot;text-align: left&quot;&gt;経営層の認識&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;現状分析&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;1〜3ヶ月目&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;コンサルに高額費用を払うが、仕様書が古く現場も「なんとなく使っている」状態。表面的なヒアリングで不完全な要件定義書が作成され、重要な例外処理や暗黙のルールは抜け落ちる&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;「順調に進んでいる」&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;SaaS選定&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;4〜8ヶ月目&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;不完全な要件定義書をもとにSaaS製品を選定。「カスタマイズすれば何とかなる」と判断するが、SaaSのカスタマイズには限界がある。データ移行計画も曖昧。予算は当初の2倍に膨張&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;「想定内の追加投資」&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;移行実施&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;9〜12ヶ月目&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;全面移行を強行し現場は大混乱。「以前できたこと」ができない、例外処理の欠落が判明、過去データが参照できず業務停止。現場から「前のシステムに戻せ」の声&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;「現場の抵抗」と認識&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;破綻&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;12ヶ月目〜&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;現行システムは停止済みで戻せない。手作業やExcelで応急対応。ベンダーは「要件定義が不十分だった」と責任回避。業務効率は移行前より悪化。責任者が退職&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;責任問題に発展&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;h2 id=&quot;7._唯一の対応策&quot;&gt;7. 唯一の対応策&lt;&#x2F;h2&gt;
&lt;p&gt;本気で脱出するなら、以下の対策が必要です。
これは「超ハードモード」であることを認識してください。&lt;&#x2F;p&gt;
&lt;p&gt;まず、業務プロセスリエンジニアリング能力の確保が必要です。
SaaSの前提とする業務プロセスを理解し、現行業務を可視化した上で
SaaSに適応させる能力が必須であり、
経験豊富な外部コンサルの支援が必要になります（高額）。&lt;&#x2F;p&gt;
&lt;p&gt;次に、捨てる覚悟と意思決定です。
現行システムの機能やデータの一部を諦める大胆な意思決定が不可欠であり、
「今と同じことができる」を目指すと必ず失敗します。&lt;&#x2F;p&gt;
&lt;p&gt;そして、現場の抵抗を押し切るコミットメントが絶対条件です。
現場の抵抗をトップダウンで押し切る経営層の覚悟と、
相応の予算を得る交渉力も必須です。&lt;&#x2F;p&gt;
&lt;p&gt;なお、移行手法として「ストラングラーパターン」（Strangler Fig Pattern）
と呼ばれる段階的移行が有効です。
一気に全面移行せず、新機能をSaaSで構築しながら徐々に旧システムの機能を
絞めていく手法です。
リスクを分散でき、途中で軌道修正も可能ですが、
この手法を採用するには移行期間中の並行運用コストを
許容できることが前提条件となります。&lt;&#x2F;p&gt;
&lt;p&gt;これらの対策には膨大な投資が必要です。
この規模の投資を経営判断として通すには、業務効率化による大幅なコスト削減、
新規事業での大きな経済効果の実現、競争優位性の獲得といった、
明確で大きなビジネス成果を示す必要があります。
単なる「技術的負債の解消」では、この規模の投資は正当化できません。&lt;&#x2F;p&gt;
&lt;!-- textlint-disable --&gt;
&lt;div class=&quot;admonition tip&quot;&gt;
    &lt;div class=&quot;admonition-icon admonition-icon-tip&quot;&gt;&lt;&#x2F;div&gt;
    &lt;div class=&quot;admonition-content&quot;&gt;
        &lt;strong class=&quot;admonition-title&quot;&gt;超ハードモードをクリアした事例：浜松倉庫株式会社&lt;&#x2F;strong&gt;
        &lt;p&gt;静岡県の中堅倉庫会社である&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.hamamatsu-soko.co.jp&#x2F;&quot;&gt;浜松倉庫&lt;&#x2F;a&gt;は、
長年使い続けたスクラッチ開発の倉庫管理システム（WMS）を3年かけて刷新し、
経済産業省「DXセレクション2024」でグランプリを受賞しました。
社内にDX人材が1人もいない状態からの出発でした。
成功の鍵は以下の3点でした。&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;経営層の全面的コミット&lt;&#x2F;strong&gt; —
社長が「10年後、20年後の会社の在り方を考えてほしい」と若手管理者に問題提起し、
従業員主体で徹底的に議論させた&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;段階的なアプローチ&lt;&#x2F;strong&gt; —
3年間を4段階に分け、ビジョン策定→課題掘り下げ→仕様書作成→導入運用と進めた&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;時間をかける覚悟&lt;&#x2F;strong&gt; —
「もし1年でやれと言われたら失敗していた」（取締役談）&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;参考：&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;j-net21.smrj.go.jp&#x2F;special&#x2F;dx&#x2F;20240924.html&quot;&gt;J-Net21 浜松倉庫事例&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;

    &lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;!-- textlint-enable --&gt;
&lt;h2 id=&quot;8._自己診断チェックリスト&quot;&gt;8. 自己診断チェックリスト&lt;&#x2F;h2&gt;
&lt;p&gt;自組織がこの「無理ゲー」状態に陥っていないか、
以下のチェックリストで確認してください。
該当項目が多いほど、移行リスクが高い状態です。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;システム管理の状態&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;現行システムの最新の仕様書・設計書が組織内に存在しない&lt;&#x2F;li&gt;
&lt;li&gt;ソースコードの所在や最新版を把握していない&lt;&#x2F;li&gt;
&lt;li&gt;システムの全機能を説明できる社内担当者がいない&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;&lt;strong&gt;ベンダー関係&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;5年以上同じベンダーにシステム保守を依存している&lt;&#x2F;li&gt;
&lt;li&gt;ベンダーの見積もりを検証する手段がない&lt;&#x2F;li&gt;
&lt;li&gt;ベンダー変更を検討したことがない、または断念した&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;&lt;strong&gt;組織能力&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;CIOまたはIT統括責任者が不在である&lt;&#x2F;li&gt;
&lt;li&gt;業務要件を自ら定義した経験がない&lt;&#x2F;li&gt;
&lt;li&gt;トップダウンでの業務改革を実施した経験がない&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;3項目以上該当する場合は要注意です。
まずは小さな領域から仕様の可視化と文書化を始め、
段階的にIT統制能力を高めていくことを検討してください。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;まとめ：経営への教訓&quot;&gt;まとめ：経営への教訓&lt;&#x2F;h2&gt;
&lt;p&gt;この状況は技術的な問題というより、組織的なガバナンスの喪失が根本原因です。&lt;&#x2F;p&gt;
&lt;p&gt;現状維持を続けるなら、ベンダーロックインの継続と保守費用の高騰を
受け入れるしかありません。
脱出を目指すなら、膨大な投資と困難なプロジェクト遂行が必要です。
しかもその投資は、大きなビジネス成果とセットで
経営層がコミットした場合のみ正当化できます。&lt;&#x2F;p&gt;
&lt;p&gt;「システム刷新」は手段であり、目的ではありません。
安易なIT投資と組織的なIT統制能力の放棄が、
いかに高いツケとなって返ってくるかを示す典型例です。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;まだ間に合う組織へ：今日から始められる予防策&quot;&gt;まだ間に合う組織へ：今日から始められる予防策&lt;&#x2F;h3&gt;
&lt;p&gt;このような状況を避けるため、以下の具体的なアクションを今日から始めてください。&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;仕様書・設計書の管理体制を確立する&lt;&#x2F;strong&gt; —
ConfluenceやNotionなどのドキュメント管理ツールを導入し、
システム仕様を組織内で一元管理する仕組みを作る。
ベンダーが作成した文書も必ず組織内に保管する。&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;API仕様を可視化する&lt;&#x2F;strong&gt; —
SwaggerやOpenAPI形式でシステム間連携の仕様を文書化しておくと、
将来の移行時に大きな資産となる。&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;定期的な棚卸しを実施する&lt;&#x2F;strong&gt; —
年1回程度、システムの機能一覧と利用状況を棚卸しし、
不要な機能の廃止や仕様の最新化を行う。&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;複数ベンダーとの関係を維持する&lt;&#x2F;strong&gt; —
現行ベンダー以外とも定期的に情報交換し、
技術動向の把握と比較検討の材料を確保する。&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;社内にIT人材を育成する&lt;&#x2F;strong&gt; —
外部に完全依存せず、最低限の技術判断ができる人材を社内に確保する。&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;h3 id=&quot;すでにこの状況に陥っている組織へ&quot;&gt;すでにこの状況に陥っている組織へ&lt;&#x2F;h3&gt;
&lt;p&gt;絶望する必要はありません。ただし、短期間での劇的な改善は期待できません。
まずは経営層の理解を得ることから始め、
小さな領域から段階的に状況を改善していくアプローチが現実的です。
最初の一歩は、現状を正確に把握し、経営層と共有することです。&lt;&#x2F;p&gt;
</content>
        <summary type="html">IT部門が弱い組織で塩漬けシステムが「無理ゲー」になる構造を解説します。
ブラックボックス化・ベンダーロックイン・組織能力不足が絡み合う
負のスパイラルと、その脱出策を具体的に示します。
</summary>
        </entry><entry xml:lang="en">
        <title>ブログをZolaに移行、AWSの後始末</title>
        <published>2026-01-30T00:00:00+00:00</published>
        <updated>2026-01-30T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2026/01/blog-to-zola-aws-cleanup/" type="text/html"/>
        <id>https://codedchords.dev/blog/2026/01/blog-to-zola-aws-cleanup/</id>
        
            <content type="html">&lt;!-- textlint-disable --&gt;
&lt;div class=&quot;full-width&quot;&gt;
    &lt;img src=&quot;https:&amp;#x2F;&amp;#x2F;codedchords.dev&amp;#x2F;blog&amp;#x2F;2026&amp;#x2F;01&amp;#x2F;blog-to-zola-aws-cleanup&amp;#x2F;.&amp;#x2F;zola.webp?h=97404862aa35036da55c&quot; alt=&quot;Zola&quot; width=&quot;1194&quot; height=&quot;716&quot; loading=&quot;lazy&quot;&#x2F;&gt;
&lt;&#x2F;div&gt;
&lt;!-- textlint-enable --&gt;
&lt;details&gt;
&lt;summary&gt;Table of Contents&lt;&#x2F;summary&gt;
&lt;!-- toc --&gt;
&lt;&#x2F;details&gt;
&lt;p&gt;技術検証目的で1年ほどNext.js + Amazon Amplify構成のブログを運用していました。
目的も達成したので静的サイトジェネレーター(以下、SSGと記載)に移行しましたが、意外と移行先の選定や
AWSの後始末に手間取りました。その記録を残します。&lt;&#x2F;p&gt;
&lt;span id=&quot;continue-reading&quot;&gt;&lt;&#x2F;span&gt;&lt;h2 id=&quot;Zola_への移行&quot;&gt;Zola への移行&lt;&#x2F;h2&gt;
&lt;p&gt;移行先のSSGには &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.getzola.org&#x2F;&quot;&gt;Zola&lt;&#x2F;a&gt; を選びました。&lt;&#x2F;p&gt;
&lt;p&gt;Python系（&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;getpelican.com&#x2F;&quot;&gt;Pelican&lt;&#x2F;a&gt;, &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;getnikola.com&#x2F;&quot;&gt;Nikola&lt;&#x2F;a&gt;）は
以前使った経験があり、遅さに辟易していたので避けました。
&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;gohugo.io&#x2F;&quot;&gt;Hugo&lt;&#x2F;a&gt; も使用経験があるため、比較的新しく人気のあるZolaを
選びました。
Rust製のシングルバイナリで、node_modulesやpip installが不要です。&lt;&#x2F;p&gt;
&lt;p&gt;MDX形式の200記事程度あったので、 Markdownへの変換は、Claude Codeで作成した
&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;yostos&#x2F;blog-yostos&#x2F;blob&#x2F;main&#x2F;tools&#x2F;convert_mdx.py&quot;&gt;移行ツール&lt;&#x2F;a&gt;
で対応しました。&lt;&#x2F;p&gt;
&lt;p&gt;ホスティング先はCloudflareを想定していました。&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;サービス&lt;&#x2F;th&gt;&lt;th&gt;Zola 対応&lt;&#x2F;th&gt;&lt;th&gt;備考&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;Cloudflare Pages&lt;&#x2F;td&gt;&lt;td&gt;V1 のみ&lt;&#x2F;td&gt;&lt;td&gt;V2&#x2F;V3 で &lt;code&gt;zola: not found&lt;&#x2F;code&gt; エラー&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Netlify&lt;&#x2F;td&gt;&lt;td&gt;あり&lt;&#x2F;td&gt;&lt;td&gt;2025年9月〜 月20デプロイ制限&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;GitHub Pages&lt;&#x2F;td&gt;&lt;td&gt;GitHub Actions&lt;&#x2F;td&gt;&lt;td&gt;制限なし、無料&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;Cloudflare PagesはV2以降で &lt;code&gt;ZOLA_VERSION&lt;&#x2F;code&gt; 環境変数を無視する問題があります。
&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;cloudflare&#x2F;pages-build-image&#x2F;issues&#x2F;3&quot;&gt;Issue&lt;&#x2F;a&gt; も2年放置されています。
Netlifyは無料プランのデプロイ制限が厳しいため、GitHub Pages + Cloudflare CDNを採用しました。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;AWS_リソースの調査と閉鎖&quot;&gt;AWS リソースの調査と閉鎖&lt;&#x2F;h2&gt;
&lt;p&gt;移行で最も手間がかかったのはAWSの閉鎖です。
Amplifyは便利ですが、裏でCloudFront、S3、IAMロールなど多くのリソースを自動生成します。
管理コンソールでは複数サービスの画面を行き来することになり、見落としが発生しやすいと感じました。
そのため、今回はすべてCLIで調査・削除しました。&lt;&#x2F;p&gt;
&lt;p&gt;まず、Amplifyが作成した可能性のあるリソースを網羅的に確認します。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# Amplify アプリ一覧（リージョン指定必須）&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;aws&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; amplify list-apps --region ap-northeast-1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# CloudFront ディストリビューション&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;aws&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; cloudfront list-distributions&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt;  --query &amp;#39;DistributionList.Items[*].[Id,Origins.Items[0].DomainName,Status]&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;  --output table&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# S3 バケット（Amplify が作成したバケットを探す）&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;aws&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; s3 ls&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; |&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; grep&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt; -E &amp;#39;amplify|blog&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# IAM ロール（Amplify 関連）&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;aws&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; iam list-roles&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt;  --query &amp;#39;Roles[?contains(RoleName,`amplify`)].RoleName&amp;#39; --output table&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# ACM 証明書（カスタムドメイン用、us-east-1 固定）&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;aws&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; acm list-certificates --region us-east-1&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt;  --query &amp;#39;CertificateSummaryList[*].[DomainName,CertificateArn]&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;  --output table&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;今回確認されたリソースと、Amplifyアプリ削除時の自動削除有無は以下の通りです。&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;サービス&lt;&#x2F;th&gt;&lt;th&gt;リソース&lt;&#x2F;th&gt;&lt;th&gt;自動削除&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;Amplify&lt;&#x2F;td&gt;&lt;td&gt;blog-yostos アプリ&lt;&#x2F;td&gt;&lt;td&gt;-&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;CloudFront&lt;&#x2F;td&gt;&lt;td&gt;Amplify 管理のディストリビューション&lt;&#x2F;td&gt;&lt;td&gt;✓&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;S3&lt;&#x2F;td&gt;&lt;td&gt;amplify-xxx-deployment バケット&lt;&#x2F;td&gt;&lt;td&gt;✓&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;IAM&lt;&#x2F;td&gt;&lt;td&gt;AmplifySSRLoggingRole 等&lt;&#x2F;td&gt;&lt;td&gt;✗&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;ACM&lt;&#x2F;td&gt;&lt;td&gt;blog.yostos.org 証明書&lt;&#x2F;td&gt;&lt;td&gt;✗&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;調査が終わったら、リソースを削除していきます。&lt;&#x2F;p&gt;
&lt;!-- textlint-disable --&gt;
&lt;div class=&quot;admonition warning&quot;&gt;
    &lt;div class=&quot;admonition-icon admonition-icon-warning&quot;&gt;&lt;&#x2F;div&gt;
    &lt;div class=&quot;admonition-content&quot;&gt;
        &lt;strong class=&quot;admonition-title&quot;&gt;削除作業の注意&lt;&#x2F;strong&gt;
        &lt;p&gt;以下ではコマンド例を示していますが、実際の削除作業では各コマンドの出力を目視で
確認し、削除対象が正しいことを1つずつ確かめながら進めました。
AWSリソースの削除は取り消しができないため、慎重に作業することをおすすめします。&lt;&#x2F;p&gt;

    &lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;!-- textlint-enable --&gt;
&lt;p&gt;Amplify Hosting（WEB_COMPUTEタイプ）の場合、アプリを削除するとCloudFrontと
S3バケットは自動削除されます。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# アプリ ID を確認して削除&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;aws&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; amplify list-apps --region ap-northeast-1&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt;  --query &amp;#39;apps[?name==`blog-yostos`].appId&amp;#39; --output text&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;aws&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; amplify delete-app --app-id&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; &amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;APP_I&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;D&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; --region ap-northeast-1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;IAMロールは自動削除されないため、手動で削除します。ロールを削除する前に、
アタッチされているポリシーをすべてデタッチする必要があります。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# ロールにアタッチされたポリシーを確認&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;aws&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; iam list-attached-role-policies --role-name&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; &amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;ROLE_NAM&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;E&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;aws&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; iam list-role-policies --role-name&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; &amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;ROLE_NAM&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;E&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# ポリシーをデタッチしてからロールを削除&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;aws&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; iam detach-role-policy --role-name&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; &amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;ROLE_NAM&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;E&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; --policy-arn&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; &amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;POLICY_AR&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;N&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;aws&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; iam delete-role --role-name&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; &amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;ROLE_NAM&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;E&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;ACM証明書はCloudFrontで使用中だと削除できないため、CloudFront削除後に
実行します。ACM証明書はus-east-1リージョン固定です。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;aws&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; acm list-certificates --region us-east-1&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt;  --query &amp;#39;CertificateSummaryList[?DomainName==`blog.yostos.org`]&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;aws&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; acm delete-certificate --certificate-arn&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; &amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;CERT_AR&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;N&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; --region us-east-1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;DNSはFastmailで管理していたため、Amplify用のCNAMEレコードを削除し、
GitHub Pages用の設定に変更しました。&lt;&#x2F;p&gt;
&lt;p&gt;削除後は、各リソースが消えていることを確認します。CloudTrailで削除イベントも
確認できます。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# CloudFront（Amplify 管理分が消えていること）&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;aws&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; cloudfront list-distributions&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt;  --query &amp;#39;DistributionList.Items[*].Id&amp;#39; --output text&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# S3（amplify 関連バケットが消えていること）&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;aws&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; s3 ls&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; |&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; grep&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; amplify&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# CloudTrail で削除イベントを確認&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;aws&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; cloudtrail lookup-events&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;  --lookup-attributes AttributeKey=EventName,AttributeValue=DeleteApp&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;  --region ap-northeast-1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;まとめ&quot;&gt;まとめ&lt;&#x2F;h2&gt;
&lt;p&gt;Zolaはシングルバイナリで依存関係がなく、node_modulesの管理から解放されます。
Rust製で高速、テンプレートエンジンもJinja2ライクで書きやすいです。プラグイン
なしでSASSコンパイルやシンタックスハイライトまで対応しており、長期運用での
保守コストの低さが魅力です。GitHub Pages + Cloudflare CDNの構成も安定して
います。&lt;&#x2F;p&gt;
&lt;p&gt;Amazon Amplifyは構築が簡単な反面、閉鎖時は複数サービスにまたがるリソースの確認が
必要です。CloudFrontとS3はAmplifyアプリ削除時に自動削除されますが、IAM
ロール、ACM証明書、DNSレコードは手動削除が必要です。
管理コンソールでは見落としが発生しやすく、かといって個人ブログでCloudFormationを使うほどでもない。
そんなケースではCLIで網羅的に確認し、ログに残しながら作業を進めると安心です。&lt;&#x2F;p&gt;
</content>
        <summary type="html">技術検証目的で1年ほど運用していたNext.js + Amazon Amplify
構成のブログを、静的サイトジェネレーターZolaに移行しました。
移行先の選定、200記事のMarkdown変換、そしてAWSリソースの
網羅的な削除作業まで、移行の記録を残します。
</summary>
        </entry><entry xml:lang="en">
        <title>上司に説明できる生成AIガイドライン - NIST AI RMF準拠Check List</title>
        <published>2026-01-29T00:00:00+00:00</published>
        <updated>2026-01-29T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2026/01/genai-governance-checklist-release/" type="text/html"/>
        <id>https://codedchords.dev/blog/2026/01/genai-governance-checklist-release/</id>
        
            <content type="html">&lt;p&gt;この記事は &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;zenn.dev&#x2F;yostos&#x2F;articles&#x2F;genai-governance-checklist-release&quot;&gt;Zenn に掲載したオリジナル記事&lt;&#x2F;a&gt; の転載です。&lt;&#x2F;p&gt;
&lt;span id=&quot;continue-reading&quot;&gt;&lt;&#x2F;span&gt; &lt;details&gt;
  &lt;summary&gt;Table of Contents&lt;&#x2F;summary&gt;
  &lt;!-- toc --&gt;
  &lt;&#x2F;details&gt;
&lt;h2 id=&quot;「来月までにガイドラインを作って」&quot;&gt;「来月までにガイドラインを作って」&lt;&#x2F;h2&gt;
&lt;p&gt;生成AIも世の中に浸透してきたので、普通の企業や団体でも利用を検討しているところが増えてきたと思います。&lt;&#x2F;p&gt;
&lt;p&gt;ある日突然、上司からこう言われる可能性はありませんか？　あるいはもう既に経験済みかも知れません。&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;「うちも生成AIを使い始めたいんだけど、まずガイドラインを作ってくれない？」&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;引き受けたものの、いざ着手すると途方に暮れます。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;何から書けばいいのか分からない&lt;&#x2F;li&gt;
&lt;li&gt;抜け漏れがあったらどうしよう&lt;&#x2F;li&gt;
&lt;li&gt;完成しても「これで大丈夫」と言い切れない&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;そんなあなたのために、チェックリストを作りました。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;yostos.github.io&#x2F;genai-governance-checklist&#x2F;&quot;&gt;https:&#x2F;&#x2F;yostos.github.io&#x2F;genai-governance-checklist&#x2F;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;このチェックリストの対象&quot;&gt;このチェックリストの対象&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;誰のためのチェックリストか&quot;&gt;誰のためのチェックリストか&lt;&#x2F;h3&gt;
&lt;p&gt;専門のIT部門を持たない中小規模の組織で、専門家ではない生成AIの利用ガイドラインを策定・点検する担当者を想定しています。&lt;&#x2F;p&gt;
&lt;p&gt;AIやリスク管理の専門知識がなくても、項目を順に確認できるよう、各項目に「説明」と「定義例」を付けています。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;何を対象としているか&quot;&gt;何を対象としているか&lt;&#x2F;h3&gt;
&lt;p&gt;ChatGPT・Claude・Gemini等のチャット型SaaS生成AIサービスを業務で利用する場面が対象です。IT部門を持たない組織では、おそらくこれらのチャット型の生成AIから始めるケースが多いと考えられるためです。&lt;&#x2F;p&gt;
&lt;p&gt;以下は対象外です。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;自社でAIモデルを開発・訓練する場面&lt;&#x2F;li&gt;
&lt;li&gt;ソフトウェア開発におけるコード生成の用途&lt;&#x2F;li&gt;
&lt;li&gt;エージェント型AIの利用（次回更新で対応予定）&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;なぜこのチェックリストが「正しい」と言えるのか&quot;&gt;なぜこのチェックリストが「正しい」と言えるのか&lt;&#x2F;h2&gt;
&lt;p&gt;ガイドラインを作ったら、次に待っているのは上司や経営層からの質問です。&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;「で、このガイドラインが正しいという根拠は何？」&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;この質問に答えられるよう、本チェックリストはNIST AI RMFを軸に構成しています。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;NISTとは何か&quot;&gt;NISTとは何か&lt;&#x2F;h3&gt;
&lt;p&gt;NIST（米国国立標準技術研究所）は、米国商務省傘下の連邦機関です。&lt;&#x2F;p&gt;
&lt;p&gt;NISTが策定する標準・ガイドラインは、米国政府機関だけでなく世界中の組織で採用されています。
サイバーセキュリティ分野ではNIST Cybersecurity Framework（CSF）が事実上の世界標準となっており、日本でも金融庁や経済産業省のガイドラインがNIST CSFを参照しています。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;NIST_AI_RMFとは何か&quot;&gt;NIST AI RMFとは何か&lt;&#x2F;h3&gt;
&lt;p&gt;AI Risk Management Framework（AI RMF 1.0）は、NISTが2023年1月に公開したAIリスク管理の国際的な基本枠組みです。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;米国議会の指示（National AI Initiative Act of 2020）に基づいて策定&lt;&#x2F;li&gt;
&lt;li&gt;産官学の幅広いステークホルダーとの協議を経て完成&lt;&#x2F;li&gt;
&lt;li&gt;AIシステムの開発・運用におけるリスク管理の4機能（GOVERN・MAP・MEASURE・MANAGE）を体系化&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;さらに2024年7月には、生成AI固有のリスクを扱う拡張文書NIST AI 600-1（Generative AI Profile）が公開されました。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;なぜNISTを軸にすべきか&quot;&gt;なぜNISTを軸にすべきか&lt;&#x2F;h3&gt;
&lt;p&gt;日本にも経済産業省やIPAのガイドラインがありますが、これらはNIST AI RMFを参照して策定されています。&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;ガイドライン&lt;&#x2F;th&gt;&lt;th&gt;NISTとの関係&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;経済産業省「AI事業者ガイドライン」&lt;&#x2F;td&gt;&lt;td&gt;NIST AI RMFの4機能を参照&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;IPA「テキスト生成AI導入・運用ガイドライン」&lt;&#x2F;td&gt;&lt;td&gt;NIST AI RMFを基本構造として採用&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;つまり、NISTを押さえておけば、日本のガイドラインの&lt;strong&gt;上流&lt;&#x2F;strong&gt;を押さえたことになります。上司から「根拠は？」と聞かれたら、こう答えられます。&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;「米国NISTのAI RMFに基づいています。日本の経産省やIPAのガイドラインも、このNIST AI RMFを参照して策定されています」&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;h3 id=&quot;本チェックリストが参照している基準&quot;&gt;本チェックリストが参照している基準&lt;&#x2F;h3&gt;
&lt;p&gt;NISTを軸に、国内外の主要基準を横断的に参照しています。&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;略称&lt;&#x2F;th&gt;&lt;th&gt;正式名称&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;NIST&lt;&#x2F;td&gt;&lt;td&gt;NIST AI Risk Management Framework (AI RMF 1.0)&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;NIST-GAI&lt;&#x2F;td&gt;&lt;td&gt;NIST AI RMF Generative AI Profile (NIST AI 600-1)&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;METI&lt;&#x2F;td&gt;&lt;td&gt;経済産業省・総務省「AI事業者ガイドライン」&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;JDLA&lt;&#x2F;td&gt;&lt;td&gt;日本ディープラーニング協会「生成AIの利用ガイドライン」&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;IPA&lt;&#x2F;td&gt;&lt;td&gt;IPA「テキスト生成AI導入・運用ガイドライン」&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;EU-AIA&lt;&#x2F;td&gt;&lt;td&gt;EU AI Act（EU AI規制法）&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;AIACT-JP&lt;&#x2F;td&gt;&lt;td&gt;AI推進法（人工知能関連技術の研究開発及び活用の推進に関する法律）&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;h2 id=&quot;今すぐ使う3ステップ&quot;&gt;今すぐ使う3ステップ&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;1._チェックリストを開く&quot;&gt;1. チェックリストを開く&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;yostos.github.io&#x2F;genai-governance-checklist&#x2F;&quot;&gt;https:&#x2F;&#x2F;yostos.github.io&#x2F;genai-governance-checklist&#x2F;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;全7章・120項目。各項目に「説明」と「定義例」が付いています。まだガイドライン策定に着手してなければ、説明を読んで、これから執筆すべき項目を検討できます。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;2._Excel版で現状を点検する&quot;&gt;2. Excel版で現状を点検する&lt;&#x2F;h3&gt;
&lt;p&gt;もし策定したガイドラインがある、あるいは執筆済みである場合は、EXCELでチェックリストを用意しました。自組織のガイドラインと突き合わせて、項目の抜け漏れを確認いただけます。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;yostos&#x2F;genai-governance-checklist&#x2F;raw&#x2F;main&#x2F;excel&#x2F;genai-governance-checklist.xlsx&quot;&gt;Excel版をダウンロード&lt;&#x2F;a&gt;して、対応状況を記入します。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;ドロップダウンで「対応済／一部対応／未対応／該当なし」を選択&lt;&#x2F;li&gt;
&lt;li&gt;サマリーシートで対応率を自動集計&lt;&#x2F;li&gt;
&lt;li&gt;まずはRequired（必須）項目の対応率100%を目指す&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;3._定義例を参考にガイドラインを書く&quot;&gt;3. 定義例を参考にガイドラインを書く&lt;&#x2F;h3&gt;
&lt;p&gt;各項目の「定義例」を参考に、自組織向けにカスタマイズしてください。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;1.1.A. [Required] 生成AI利用に関する最終責任者（経営層）が&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;明確に定められている [NIST: GOVERN 2.3] [METI]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  説明: AI関連の最終判断を下す責任者は必須。責任者が不明確だと、&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  インシデント発生時に判断が遅れ法的・社会的リスクを組織全体に&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  波及させる。&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  定義例: 「団体理事長をAI利用の最終責任者とし、利用方針の承認・&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  リスク受容の判断・重大インシデント時の意思決定を自ら行う」&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;「何を書けばいいか分からない」状態から脱出できます。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;準拠レベルで優先度が明確&quot;&gt;準拠レベルで優先度が明確&lt;&#x2F;h2&gt;
&lt;p&gt;各項目には準拠レベルが設定されています。限られた時間で何を優先すべきかが一目で分かります。年間予算15億円程度の非営利団体を想定し定義内容に基づいて独自にセットしたものです。業種によって事情が異なると思いますが、設定理由もドキュメントに残していますので必要応じて見直し下さい。&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;準拠レベル&lt;&#x2F;th&gt;&lt;th&gt;意味&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;Required&lt;&#x2F;td&gt;&lt;td&gt;必ず記載すべき。欠落すると法令違反や重大リスクにつながる&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Recommended&lt;&#x2F;td&gt;&lt;td&gt;記載を強く推奨。除外する場合は理由を説明できること&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Option&lt;&#x2F;td&gt;&lt;td&gt;記載があると望ましい。組織の規模や業種に応じて検討&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;h2 id=&quot;チェックリストの構成&quot;&gt;チェックリストの構成&lt;&#x2F;h2&gt;
&lt;p&gt;NIST AI RMFの4機能（GOVERN・MAP・MEASURE・MANAGE）に沿って構成しています。&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;章&lt;&#x2F;th&gt;&lt;th&gt;タイトル&lt;&#x2F;th&gt;&lt;th&gt;項目数&lt;&#x2F;th&gt;&lt;th&gt;概要&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;1&lt;&#x2F;td&gt;&lt;td&gt;ガバナンス体制&lt;&#x2F;td&gt;&lt;td&gt;21&lt;&#x2F;td&gt;&lt;td&gt;責任者・ポリシー・教育など組織の管理体制&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;2&lt;&#x2F;td&gt;&lt;td&gt;リスクの特定と評価&lt;&#x2F;td&gt;&lt;td&gt;21&lt;&#x2F;td&gt;&lt;td&gt;利用目的の明確化とリスクアセスメント&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;3&lt;&#x2F;td&gt;&lt;td&gt;入力データの管理&lt;&#x2F;td&gt;&lt;td&gt;16&lt;&#x2F;td&gt;&lt;td&gt;入力禁止情報・個人情報・機密情報の取り扱い&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;4&lt;&#x2F;td&gt;&lt;td&gt;出力の管理と利用&lt;&#x2F;td&gt;&lt;td&gt;15&lt;&#x2F;td&gt;&lt;td&gt;出力の検証義務・著作権・利用範囲&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;5&lt;&#x2F;td&gt;&lt;td&gt;信頼性の確保&lt;&#x2F;td&gt;&lt;td&gt;31&lt;&#x2F;td&gt;&lt;td&gt;正確性・安全性・公平性・透明性などの品質特性&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;6&lt;&#x2F;td&gt;&lt;td&gt;インシデント対応&lt;&#x2F;td&gt;&lt;td&gt;4&lt;&#x2F;td&gt;&lt;td&gt;報告体制と対応手順&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;7&lt;&#x2F;td&gt;&lt;td&gt;ガイドラインとしての完成度&lt;&#x2F;td&gt;&lt;td&gt;12&lt;&#x2F;td&gt;&lt;td&gt;文書としての一般的な品質要件&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;h2 id=&quot;リンク集&quot;&gt;リンク集&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;オンライン版: &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;yostos.github.io&#x2F;genai-governance-checklist&#x2F;&quot;&gt;https:&#x2F;&#x2F;yostos.github.io&#x2F;genai-governance-checklist&#x2F;&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;GitHubリポジトリ: &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;yostos&#x2F;genai-governance-checklist&quot;&gt;https:&#x2F;&#x2F;github.com&#x2F;yostos&#x2F;genai-governance-checklist&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;Excel版: &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;yostos&#x2F;genai-governance-checklist&#x2F;raw&#x2F;main&#x2F;excel&#x2F;genai-governance-checklist.xlsx&quot;&gt;genai-governance-checklist.xlsx&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;MITライセンスで公開しています。商用・非商用問わず自由に利用できます。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;作成プロセス&quot;&gt;作成プロセス&lt;&#x2F;h2&gt;
&lt;p&gt;本チェックリストは&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;docs.anthropic.com&#x2F;ja&#x2F;docs&#x2F;claude-code&quot;&gt;Claude Code&lt;&#x2F;a&gt;を全面的に活用し、コンセプト検討→計画→作成→インスペクションのプロセスで作成しました。&lt;&#x2F;p&gt;
&lt;p&gt;インスペクションにはMAGIシステム&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-magi-1&quot;&gt;&lt;a href=&quot;#fn-magi&quot;&gt;1&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;を使用しました。3つの異なる視点を持つAIエージェントが並列でレビューし、指摘を統合することで、単一視点では見落としがちな問題を検出できました。&lt;&#x2F;p&gt;
&lt;p&gt;インスペクションログは&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;yostos&#x2F;genai-governance-checklist&#x2F;tree&#x2F;main&#x2F;docs&quot;&gt;docsフォルダ&lt;&#x2F;a&gt;で公開しています。&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;現在v1.0.0-rc.1（リリース候補版）です。フィードバックを募集しています。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;yostos&#x2F;genai-governance-checklist&#x2F;issues&quot;&gt;https:&#x2F;&#x2F;github.com&#x2F;yostos&#x2F;genai-governance-checklist&#x2F;issues&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;section class=&quot;footnotes&quot;&gt;
&lt;ol class=&quot;footnotes-list&quot;&gt;
&lt;li id=&quot;fn-magi&quot;&gt;
&lt;p&gt;MAGIシステムは、Claude Codeプラグインとして実装した品質レビューシステムです。エヴァンゲリオンのMAGIから着想を得て、CASPER（批判的分析）・BALTHASAR（実用性評価）・MELCHIOR（創造的提案）の3エージェントが独立してレビューします。詳細は &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;yostos&#x2F;claude-code-plugins&quot;&gt;https:&#x2F;&#x2F;github.com&#x2F;yostos&#x2F;claude-code-plugins&lt;&#x2F;a&gt; を参照してください。 &lt;a href=&quot;#fr-magi-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;&#x2F;section&gt;
</content>
        <summary type="html">NIST AI RMF準拠の生成AIガバナンスチェックリストを公開しました。
ChatGPT・Claude・Gemini等のSaaS型生成AIを業務利用する際の
ガイドライン策定に使える、全7章・120項目の実践的な内容です。
非専門家でも使いやすく、小規模な組織でも今すぐ始められます。
</summary>
        </entry><entry xml:lang="en">
        <title>多機能Todoに疲れた人へ ─「一枚の紙」だけのタスク管理CLI</title>
        <published>2026-01-23T00:00:00+00:00</published>
        <updated>2026-01-23T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2026/01/building-ttt-with-claude-code/" type="text/html"/>
        <id>https://codedchords.dev/blog/2026/01/building-ttt-with-claude-code/</id>
        
            <content type="html"> &lt;details&gt;
  &lt;summary&gt;Table of Contents&lt;&#x2F;summary&gt;
  &lt;!-- toc --&gt;
  &lt;&#x2F;details&gt;
&lt;h2 id=&quot;はじめに&quot;&gt;はじめに&lt;&#x2F;h2&gt;
&lt;p&gt;ターミナルで作業中、ふと「あれもやらなきゃ」と思いついたとき、頭の中を書き出す場所が欲しくなります。
物理的なメモ用紙ならすぐに書けますが、ターミナルから手を離すのは煩わしい。
かといって多機能なTodoアプリを開くと、プロジェクトやタグを考えているうちに書きたかったことを忘れてしまう。&lt;&#x2F;p&gt;
&lt;p&gt;そこで作ったのが &lt;strong&gt;Tiny Task Tool&lt;&#x2F;strong&gt; です。コマンド名はタイプしやすいように &lt;code&gt;ttt&lt;&#x2F;code&gt; としました。&lt;&#x2F;p&gt;
&lt;p&gt;「一枚の紙」のシンプルさをターミナルで再現することを目指した、ミニマルなタスク管理ツールです。&lt;&#x2F;p&gt;
&lt;p&gt;この記事では、&lt;code&gt;ttt&lt;&#x2F;code&gt; のコンセプトと使い方を紹介しつつ、Claude Codeとの協働開発でドキュメント駆動とTDDがいかに効果的だったかをお伝えします。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;Tiny_Task_Tool_とは&quot;&gt;Tiny Task Tool とは&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;code&gt;ttt&lt;&#x2F;code&gt;(Tiny Task Tool) は「デジタルなメモ用紙」を目指したTUIタスク管理ツールです。&lt;&#x2F;p&gt;
&lt;!-- textlint-disable --&gt;
&lt;img
  src=&quot;https:&amp;#x2F;&amp;#x2F;codedchords.dev&amp;#x2F;blog&amp;#x2F;2026&amp;#x2F;01&amp;#x2F;building-ttt-with-claude-code&amp;#x2F;demo.gif?h=5668a44b60ecfc9113e6&quot;
  alt=&quot;ttt demo&quot; width=&quot;800&quot; height=&quot;600&quot; loading=&quot;lazy&quot;
&#x2F;&gt;&lt;!-- textlint-enable --&gt;
&lt;h3 id=&quot;主な特徴&quot;&gt;主な特徴&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;一枚の紙&lt;&#x2F;strong&gt;: ファイルは常に1つ。「どのファイルに書こう」という選択を排除&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;今に集中&lt;&#x2F;strong&gt;: タスクをすぐ書き出し、完了したらアーカイブ。シンプルな運用&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;ノード指向&lt;&#x2F;strong&gt;: 階層構造のタスクを直感的に扱える。親を完了すれば子も完了&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Unix 哲学&lt;&#x2F;strong&gt;: フォーカス機能以外は外部エディタやGitに任せる&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;インストール&quot;&gt;インストール&lt;&#x2F;h3&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# go install（推奨）&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;go&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; install github.com&#x2F;yostos&#x2F;tiny-task-tool@latest&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# Homebrew&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;brew&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; install yostos&#x2F;tap&#x2F;ttt&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;基本的な使い方&quot;&gt;基本的な使い方&lt;&#x2F;h3&gt;
&lt;p&gt;ターミナルで &lt;code&gt;ttt&lt;&#x2F;code&gt; と打つだけで、1ページのタスク表がTUIで開きます。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;ttt&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;                    # TUIでタスク表を開く&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;ttt&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt; -t &amp;quot;牛乳を買う&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;     # コマンドラインからタスクを追加&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;ttt&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; sync&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;               # git pushでリモートと同期&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;TUIでは &lt;code&gt;e&lt;&#x2F;code&gt; でエディタを開き、&lt;code&gt;a&lt;&#x2F;code&gt; でアーカイブ、&lt;code&gt;q&lt;&#x2F;code&gt; で終了。キーバインドはVim&#x2F;Emacsユーザー向けにカスタマイズ可能です。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;タスクのフォーマット&quot;&gt;タスクのフォーマット&lt;&#x2F;h3&gt;
&lt;p&gt;シンプルなMarkdownチェックボックス形式です。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;markdown&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-list z-begin z-markdown&quot;&gt;-&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt; [ ] 未完了のタスク&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-list z-begin z-markdown&quot;&gt;-&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-link z-title z-string z-other z-link z-title z-markdown&quot;&gt; [x]&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt; 完了したタスク @done(2026-01-18)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-list z-begin z-markdown&quot;&gt;  -&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-link z-title z-string z-other z-link z-title z-markdown&quot;&gt; [x]&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt; 子タスクも自動で完了 @done(2026-01-18)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;タスク以外の箇条書きもノードとして挿入できます。タスクをグルーピングするためにセクション（&lt;code&gt;# Task&lt;&#x2F;code&gt; や &lt;code&gt;## Project A&lt;&#x2F;code&gt;）なども扱えます。&lt;&#x2F;p&gt;
&lt;p&gt;完了したタスクには自動で &lt;code&gt;@done(日付)&lt;&#x2F;code&gt; タグが付き、設定した日数が経過するとarchive.mdに移動します。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;なぜ作ったのか&quot;&gt;なぜ作ったのか&lt;&#x2F;h2&gt;
&lt;p&gt;きっかけはZennで見かけた「&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;zenn.dev&#x2F;nekoninaritai&#x2F;articles&#x2F;941e55aed77609&quot;&gt;Markdown Paper という選択肢&lt;&#x2F;a&gt;」という記事でした。&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;ephe.app&#x2F;&quot;&gt;ephe.app&lt;&#x2F;a&gt; の「一枚の紙」コンセプトをCLIに持ち込んだ &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;siki-712&#x2F;aeph&quot;&gt;aeph&lt;&#x2F;a&gt; の紹介記事です。&lt;&#x2F;p&gt;
&lt;p&gt;コンセプトには共感しましたが、aephは複数ファイルに対応しており、「一枚の紙」とは少し違うと感じました。そこでaephのソースコードを参考にするのではなく、ゼロから自分のコンセプトで作ることにしました。&lt;&#x2F;p&gt;
&lt;p&gt;既存のツールにも同様の問題がありました。&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Todo アプリ&lt;&#x2F;strong&gt;: 多機能すぎる。プロジェクト、優先度、タグ…考えているうちに書きたいことを忘れる&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Markdown エディタ&lt;&#x2F;strong&gt;: ファイル名やフォルダを考える必要がある&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;GUI アプリ&lt;&#x2F;strong&gt;: ターミナルから離れるコンテキストスイッチが発生する&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;単一ファイル、選択肢なし、気を散らすものなし。机の上のメモ用紙のように、「開いて、書いて、終わったら消す」だけの体験が欲しかったのです。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;Claude_Code_との開発体験&quot;&gt;Claude Code との開発体験&lt;&#x2F;h2&gt;
&lt;p&gt;このプロジェクトはClaude Codeを活用し、以下のプロセスで開発しました。&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;コンセプト文書化（concept.md）&lt;&#x2F;li&gt;
&lt;li&gt;詳細仕様策定（specification.md）&lt;&#x2F;li&gt;
&lt;li&gt;アーキテクチャ選定（architecture.md）&lt;&#x2F;li&gt;
&lt;li&gt;テストコード先行開発&lt;&#x2F;li&gt;
&lt;li&gt;実装&lt;&#x2F;li&gt;
&lt;li&gt;テスト自動化&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;h3 id=&quot;ドキュメント駆動が効いた理由&quot;&gt;ドキュメント駆動が効いた理由&lt;&#x2F;h3&gt;
&lt;p&gt;Claude Codeとの協働で最も効果的だったのは、&lt;strong&gt;まずドキュメントを書き、それに従って開発する&lt;&#x2F;strong&gt;アプローチでした。&lt;&#x2F;p&gt;
&lt;h4 id=&quot;1._concept.md_で方向性を固める&quot;&gt;1. concept.md で方向性を固める&lt;&#x2F;h4&gt;
&lt;p&gt;最初に「なぜ作るのか」「何をしないか」を明確にしました。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;markdown&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-heading z-markdown z-heading z-\33  z-markdown&quot;&gt;### やらないこと&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-list z-begin z-markdown&quot;&gt;-&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt; ファイル指定（「どのファイルを開くか」という選択を排除）&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-list z-begin z-markdown&quot;&gt;-&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt; 複数ファイル管理（一枚の紙の原則に反する）&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-list z-begin z-markdown&quot;&gt;-&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt; ファイル内編集（外部エディタに任せる）&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;「やらないこと」を明文化したことで、開発中に機能追加の誘惑が来ても「concept.mdに反する」と判断できました。Claudeにも「この機能はconcept.mdの方針に反しますね」とフィードバックを受けられます。&lt;&#x2F;p&gt;
&lt;h4 id=&quot;2._specification.md_で仕様を詳細化&quot;&gt;2. specification.md で仕様を詳細化&lt;&#x2F;h4&gt;
&lt;p&gt;ユースケース、画面レイアウト、エラー処理まで事前に定義しました。これによりClaudeへの指示が明確になり、生成されるコードの品質が上がりました。&lt;&#x2F;p&gt;
&lt;h4 id=&quot;3._architecture.md_で技術選定を記録&quot;&gt;3. architecture.md で技術選定を記録&lt;&#x2F;h4&gt;
&lt;p&gt;「なぜその技術を選んだか」「他の選択肢をなぜ却下したか」を記録しました。後から見返したとき、またClaudeに文脈を伝えるときに役立ちました。基本的に記載方法は &lt;strong&gt;Architectural Decision Record（ADR）形式&lt;&#x2F;strong&gt; を採用して記載しています。&lt;&#x2F;p&gt;
&lt;p&gt;以下は言語選定の際の例です。&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;候補&lt;&#x2F;th&gt;&lt;th&gt;却下理由&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;Rust&lt;&#x2F;td&gt;&lt;td&gt;学習コストが高い。所有権&#x2F;ライフタイムの概念が独特で、AI 駆動開発でコンパイルエラー修正時に堂々巡りするリスク&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Python&lt;&#x2F;td&gt;&lt;td&gt;PEP 668 により配布が複雑化。起動速度も遅い&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;TypeScript&lt;&#x2F;td&gt;&lt;td&gt;単一バイナリ配布ができず「摩擦をなくす」原則に反する&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;h3 id=&quot;TDD_が_AI_駆動開発と相性が良い理由&quot;&gt;TDD が AI 駆動開発と相性が良い理由&lt;&#x2F;h3&gt;
&lt;p&gt;テスト駆動開発（TDD）はClaude Codeとの開発で特に威力を発揮しました。&lt;&#x2F;p&gt;
&lt;h4 id=&quot;テストファーストのメリット&quot;&gt;テストファーストのメリット&lt;&#x2F;h4&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;期待動作の明確化&lt;&#x2F;strong&gt;: テストコードが「仕様書」として機能し、開発前に私が確認できるためClaudeへの指示が曖昧にならない&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;リグレッション防止&lt;&#x2F;strong&gt;: AIが生成したコードの変更が既存機能を壊していないか即座に確認&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;リファクタリングの安心感&lt;&#x2F;strong&gt;: テストが通れば安心して改善できる&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;h4 id=&quot;実際の開発フロー&quot;&gt;実際の開発フロー&lt;&#x2F;h4&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# 1. まずテストを書く（Red）&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; go test .&#x2F;...&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# FAIL: TestArchiveCompletedTasks - 期待する動作のテストが失敗&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# 2. Claude に実装を依頼&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# 「このテストを通す実装をお願いします」&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# 3. テストが通ることを確認（Green）&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; go test .&#x2F;...&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# PASS&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# 4. リファクタリング&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# 「この実装をより読みやすくリファクタリングしてください」&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;特に階層タスクのアーカイブ処理のような複雑なロジックでは、テストケースを先に書いておくことで、エッジケースの考慮漏れを防げました。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;Claude_Code_との対話で心がけたこと&quot;&gt;Claude Code との対話で心がけたこと&lt;&#x2F;h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;ドキュメントを参照させる&lt;&#x2F;strong&gt;:「concept.mdの方針に従って」「specification.mdの仕様通りに」&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;小さな単位で依頼&lt;&#x2F;strong&gt;: 一度に多くを頼まず、テスト→実装→確認のサイクルを回す&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;コミットを細かく&lt;&#x2F;strong&gt;: 動作確認できた時点でコミット。戻れるポイントを作る&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;h2 id=&quot;技術スタック&quot;&gt;技術スタック&lt;&#x2F;h2&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;分野&lt;&#x2F;th&gt;&lt;th&gt;選択&lt;&#x2F;th&gt;&lt;th&gt;理由&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;言語&lt;&#x2F;td&gt;&lt;td&gt;Go&lt;&#x2F;td&gt;&lt;td&gt;単一バイナリ配布、高速起動&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;TUI&lt;&#x2F;td&gt;&lt;td&gt;bubbletea + lipgloss&lt;&#x2F;td&gt;&lt;td&gt;成熟したエコシステム、Elm アーキテクチャ&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;設定&lt;&#x2F;td&gt;&lt;td&gt;pelletier&#x2F;go-toml v2&lt;&#x2F;td&gt;&lt;td&gt;TOML 1.0 準拠、高速&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;テスト&lt;&#x2F;td&gt;&lt;td&gt;testing + testify&lt;&#x2F;td&gt;&lt;td&gt;標準+簡潔なアサーション&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;h2 id=&quot;まとめ&quot;&gt;まとめ&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;code&gt;ttt&lt;&#x2F;code&gt; は「一枚の紙」という思想にこだわった結果、機能を削ることで価値を磨けたツールになったと思います。私自身も便利に使っています。もっと高機能なツールはたくさん
ありますが、コンセプトに賛同いただける多くの方に使ってもらえれば幸いです。&lt;&#x2F;p&gt;
&lt;p&gt;Claude Codeとの開発では、&lt;strong&gt;ドキュメント駆動&lt;&#x2F;strong&gt; と &lt;strong&gt;TDD&lt;&#x2F;strong&gt; の組み合わせが非常に効果的でした。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;ドキュメント駆動&lt;&#x2F;strong&gt;: 要件だけでなく方針を文書化するところから、Claude Codeと協働する&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;TDD&lt;&#x2F;strong&gt;: 期待動作を定義し、品質を担保する&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;「Claude Codeに任せきり」ではなく「Claude Codeと協働する」開発スタイルとして、このアプローチはおすすめできます。&lt;&#x2F;p&gt;
&lt;p&gt;興味を持っていただけたら、ぜひ使ってみてください。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;yostos&#x2F;tiny-task-tool&quot;&gt;https:&#x2F;&#x2F;github.com&#x2F;yostos&#x2F;tiny-task-tool&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;&lt;em&gt;この記事で紹介したドキュメント（concept.md, specification.md, architecture.md）は GitHub リポジトリの docs&#x2F; ディレクトリで公開しています。&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
</content>
        <summary type="html">多機能Todoアプリに疲れた方へ。「一枚の紙」だけのシンプルさを
再現したミニマルなタスク管理CLI「Tiny Task Tool (ttt)」を
開発しました。Claude Codeとの協働開発で実感した、
ドキュメント駆動とTDDの効果的な組み合わせをご紹介します。
</summary>
        </entry><entry xml:lang="en">
        <title>Sublime Text - 職人主義的ソフトウェアの美学と持続可能なビジネスモデル</title>
        <published>2026-01-08T00:00:00+00:00</published>
        <updated>2026-01-08T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2026/01/sublime-text/" type="text/html"/>
        <id>https://codedchords.dev/blog/2026/01/sublime-text/</id>
        
            <content type="html">&lt;details&gt;
&lt;summary&gt;
  Table of Contents
  &lt;&#x2F;summary&gt;
&lt;!-- toc --&gt;
&lt;&#x2F;details&gt;
&lt;p&gt;Sublime Textは、高速性と簡潔さを重視したクロスプラットフォームのテキストエディタです。
派手な統合機能や巨大なエコシステムを志向せず、「編集体験そのものの質」を最優先に設計されている点が最大の特徴といえます。&lt;&#x2F;p&gt;
&lt;p&gt;2008年にリリースされて以来、その圧倒的なパフォーマンスと洗練されたUIで多くの開発者に愛されてきました。
かつてはAtomやBracketsといった競合が次々と登場する中でも独自の地位を確立していましたが、
2015年のVisual Studio Codeの登場によって状況は一変しました。
Microsoftの豊富なリソースとオープンソースモデルによって急速に機能を拡充したVS Codeは、
瞬く間に開発者コミュニティの主流となったのです。&lt;&#x2F;p&gt;
&lt;p&gt;しかし、Sublime Textは市場シェアを失っても開発を継続し、現在も継続的にアップデートされています。
それを可能にしているのが、独自のビジネスモデルと一貫した設計思想です。
2026年現在もBuild 4000番台の開発が進められており、その品質は今も一級品を保ち続けています。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;1._技術的・思想的特徴&quot;&gt;1. 技術的・思想的特徴&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;1.1._圧倒的なパフォーマンス&quot;&gt;1.1. 圧倒的なパフォーマンス&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;起動が非常に速い&lt;&#x2F;li&gt;
&lt;li&gt;大規模ファイルや巨大リポジトリでも編集が軽快&lt;&#x2F;li&gt;
&lt;li&gt;入力遅延がほぼ発生しない&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Sublime Textの最大の強みは、何よりもそのパフォーマンスです。
エディタを起動してから実際に編集を開始できるまでの時間は、ほとんどの環境で1秒以内に収まります。
VS CodeがElectronベースでJavaScriptエンジンの起動コストを伴うのに対し、Sublime TextはC++ とカスタムUIツールキットで実装されており、
OSネイティブに近い起動速度を実現しています。&lt;&#x2F;p&gt;
&lt;p&gt;また、数万行を超える大規模ファイルや、数十万ファイルを含む巨大なリポジトリでも動作が重くなることはほとんどありません。
GitのLinuxカーネルリポジトリのような巨大なコードベースでも、ファイル検索や全文検索が瞬時に完了します。
これは独自の描画エンジンとインデックス機構によって実現されており、「常に軽いこと」を最優先事項として設計されているためです。&lt;&#x2F;p&gt;
&lt;p&gt;特に重要なのが、入力に対するレスポンスの速さです。キーボードからの入力が画面に反映されるまでの遅延が極めて少なく、タイピングの快適さが損なわれません。この「入力遅延のなさ」は、長時間コーディングを行う開発者にとって、想像以上に重要な要素となります。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;1.2._ミニマルで静かな_UI&quot;&gt;1.2. ミニマルで静かな UI&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;不要なアニメーションや通知が少ない&lt;&#x2F;li&gt;
&lt;li&gt;情報密度は高いが、視覚的ノイズが少ない&lt;&#x2F;li&gt;
&lt;li&gt;IDE的な自動介入を極力行わない&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Sublime Textのユーザーインターフェースは、極めて静かです。
近年のソフトウェアに多く見られる派手なアニメーションや、頻繁なポップアップ通知、自動的に表示されるヒントやサジェストといった「親切な機能」は最小限に抑えられています。&lt;&#x2F;p&gt;
&lt;p&gt;これは決して機能が貧弱だからではなく、ユーザーの集中を妨げない設計を意図的に選択した結果です。
情報密度は高く保たれており、必要な情報はすぐにアクセスできますが、視覚的なノイズは徹底的に排除されています。
エディタという道具が前面に出てくることなく、書いているコードそのものに集中できる環境が提供されているのです。&lt;&#x2F;p&gt;
&lt;p&gt;また、IDEによくある「自動的な修正」や「勝手な補完」といった介入も控えめです。
開発者が意図しないコード変更や、予期しないフォーマットが適用されることはほとんどありません。
これは一見不便に思えるかもしれませんが、自分の書いたコードを完全にコントロールしたい開発者にとっては、むしろ信頼できる特性となります。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;1.3._保守的で一貫した設計思想&quot;&gt;1.3. 保守的で一貫した設計思想&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;等幅フォント・静的フォント前提&lt;&#x2F;li&gt;
&lt;li&gt;Variable Fontの軸指定や高度なタイポグラフィ機能は非対応&lt;&#x2F;li&gt;
&lt;li&gt;フォントフォールバックや複雑な文字組みも対象外&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Sublime Textは、技術トレンドを積極的に追いかけるタイプのソフトウェアではありません。例えば、近年広まってきたVariable Font（可変フォント）の軸指定機能や、高度なタイポグラフィ機能には対応していません。また、複雑なフォントフォールバックや文字組み処理も、必要最小限にとどめられています。&lt;&#x2F;p&gt;
&lt;p&gt;これを見ると「技術的に遅れている」と感じるかもしれませんが、実際には異なります。これらの機能は確かに便利ですが、実装にはレンダリングエンジンの複雑化が伴い、結果としてパフォーマンスの低下を招きます。Sublime Textは、&lt;strong&gt;パフォーマンス低下を招く機能を意図的に排除している&lt;&#x2F;strong&gt; のです。&lt;&#x2F;p&gt;
&lt;p&gt;この姿勢は、ソフトウェア全体に一貫しています。新機能を追加する際には、常に「これはパフォーマンスに影響するか」
「これは本当にエディタに必要な機能か」という問いが立てられ、慎重に判断されています。
結果として、機能の追加ペースは遅いものの、一度実装された機能は安定しており、長期間にわたって同じように動作し続けます。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;1.4._拡張は可能だが、万能ではない&quot;&gt;1.4. 拡張は可能だが、万能ではない&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;Pythonによるプラグイン拡張&lt;&#x2F;li&gt;
&lt;li&gt;LSP対応により、現代的な言語サポート機能は充実&lt;&#x2F;li&gt;
&lt;li&gt;ただしIDE全体としての統合度はVS Codeに及ばない&lt;&#x2F;li&gt;
&lt;li&gt;エコシステムは小規模&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Sublime Textには、Pythonによるプラグイン機構が備わっており、機能を拡張可能です。Package Controlというパッケージマネージャーを使えば、コミュニティが開発した様々なプラグインを簡単にインストールできます。また、Language Server Protocol (LSP) にも対応しており、現代的なコード補完や定義ジャンプ、型チェックといった言語サポート機能は充実しています。&lt;&#x2F;p&gt;
&lt;p&gt;しかし、VS Codeのような統合開発環境としての&lt;strong&gt;トータルな統合度&lt;&#x2F;strong&gt;を期待すると、物足りなさを感じるかもしれません。デバッガやターミナル、バージョン管理といった周辺機能の統合度や、拡張機能エコシステムの規模では、VS Codeには及びません。&lt;&#x2F;p&gt;
&lt;p&gt;エコシステムも、VS Codeの巨大なマーケットプレイスと比べれば小規模です。しかし、これも設計思想の表れといえます。Sublime Textは「プラットフォーム」になることを目指しておらず、あくまで「高品質なエディタ」であり続けることを選択しているのです。必要十分な拡張性は保ちつつ、複雑化や肥大化は避けるというバランスが取られています。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;2._継続的な開発と進化&quot;&gt;2. 継続的な開発と進化&lt;&#x2F;h2&gt;
&lt;p&gt;Sublime Textは市場シェアを失った後も、着実に開発を継続しています。2024年から2025年にかけても、
複数の重要なアップデートがリリースされており、「保守的」でありながらも「停滞していない」ことを示しています。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;2.1._最近の主要アップデート&quot;&gt;2.1. 最近の主要アップデート&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;strong&gt;Build 4200（2025年5月リリース）&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;2025年5月21日にリリースされたBuild 4200では、以下の重要な変更が含まれています。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Python プラグインの近代化&lt;&#x2F;strong&gt;: Python 3.3のサポート終了を段階的に開始し、Python 3.8への移行を進めている。さらに、次の開発サイクルではPython 3.13への移行が計画されており、プラグインエコシステムの技術的負債を解消する取り組みが進められている。&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;OS サポートの見直し&lt;&#x2F;strong&gt;: 将来のバージョンでは、macOSの最低要件が10.9から10.13に引き上げられる。また、Windows 7、8、8.1のサポートが終了し、Windows 10以降が最低要件となる。この変更により、より新しいOS機能を活用できるようになる。&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;UI の柔軟性向上&lt;&#x2F;strong&gt;: サイドバーを右側に配置できる &lt;code&gt;sidebar_on_right&lt;&#x2F;code&gt; 設定が追加される。これは小さな変更に見えるが、長年のユーザー要望に応えたもの。&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;ビルドシステムの強化&lt;&#x2F;strong&gt;: ビルドシステムで &lt;code&gt;&quot;interactive&quot;: true&lt;&#x2F;code&gt; を指定することで、インタラクティブな入力ボックスを表示できるようになった。これにより、コンパイル時の引数指定などがより便利になっている。&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;構文ハイライトの刷新&lt;&#x2F;strong&gt;: SQL、ActionScript、Diff、Bash、Graphvizの構文ハイライトが書き直され、より正確で高速になった。また、ZshとTOMLの構文ハイライトが新たに追加されている。&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;&lt;strong&gt;Build 4180（2024年8月リリース）&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;2024年8月12日にリリースされたBuild 4180では、プラットフォーム固有の問題に対応しています。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Linux: KDE環境でのドラッグ＆ドロップ問題への対処（kwin 6.0.4でも修正済み）&lt;&#x2F;li&gt;
&lt;li&gt;Windows: スクロールバーをドラッグした際の動作改善&lt;&#x2F;li&gt;
&lt;li&gt;その他、複数のバグ修正&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;2.2._Language_Server_Protocol（LSP）サポートの充実&quot;&gt;2.2. Language Server Protocol（LSP）サポートの充実&lt;&#x2F;h3&gt;
&lt;p&gt;Sublime TextのLSPサポートは、近年大きく進化しています。Package Controlから利用できる &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;lsp.sublimetext.io&#x2F;&quot;&gt;LSP パッケージ&lt;&#x2F;a&gt;は、VS Codeと同等の高度な言語サポートを実現しています。&lt;&#x2F;p&gt;
&lt;p&gt;主要な言語サーバーには、以下のようなものがあります。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;LSP-typescript &#x2F; LSP-javascript&lt;&#x2F;strong&gt;: TypeScriptとJavaScriptのサポート&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;LSP-pyright &#x2F; LSP-pylsp&lt;&#x2F;strong&gt;: Pythonの型チェックと補完&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;LSP-rust-analyzer&lt;&#x2F;strong&gt;: Rustの高度なIDE機能&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;LSP-intelephense &#x2F; LSP-Phpactor&lt;&#x2F;strong&gt;: PHPの補完と定義ジャンプ&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;LSP-clangd&lt;&#x2F;strong&gt;: C&#x2F;C++ の高度な補完&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;LSP-json &#x2F; LSP-css &#x2F; LSP-html&lt;&#x2F;strong&gt;: Web開発のサポート&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;LSP-angular &#x2F; LSP-vue&lt;&#x2F;strong&gt;: モダンなフロントエンドフレームワーク&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;これらのヘルパーパッケージは、言語サーバーの自動インストールと設定を簡単にし、追加機能も提供しています。例えばLSP-pylspは2025年12月にも更新されており、エコシステムが活発に維持されていることがわかります。&lt;&#x2F;p&gt;
&lt;p&gt;興味深いのは、Sublime TextのLSP実装は同じファイルタイプに対して複数の言語サーバーを同時に実行できる点です。例えば、Pythonプロジェクト内のLSP-pyrightで一般的な機能を使いつつ、LSP-ruffでリンター警告を同時に表示するといった使い方が可能です。&lt;&#x2F;p&gt;
&lt;p&gt;このように、Sublime Textは「保守的」な設計思想を保ちながらも、現代的な開発環境に必要な機能を着実に取り込んでいます。急激な変化は起こりませんが、必要な進化は確実に続けられているのです。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;3._市場における位置づけ&quot;&gt;3. 市場における位置づけ&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;かつては高速GUIエディタの代表格&lt;&#x2F;li&gt;
&lt;li&gt;現在はニッチだが評価の高い存在&lt;&#x2F;li&gt;
&lt;li&gt;VS Codeのような統合開発環境とは競争しない立場&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;2010年代前半、Sublime Textは高速なGUIエディタの代表格として、多くの開発者に愛用されていました。TextMateの後継とも目され、Macユーザーを中心に広く普及していたのです。その影響力は大きく、VS Codeの初期バージョンはSublime Textのキーバインドやショートカットを参考にしたとも言われています。&lt;&#x2F;p&gt;
&lt;p&gt;しかし現在では、市場シェアという観点では完全にニッチな存在となりました。Stack Overflowの開発者調査でも、利用率は数パーセント程度にとどまっています。それでも、使い続けているユーザーからの評価は一貫して高く、「速さ」「安定性」「シンプルさ」を求める開発者の間では根強い支持を得ています。&lt;&#x2F;p&gt;
&lt;p&gt;興味深いのは、Sublime Textのユーザー層です。多くは、日常的にNeovimやEmacsといったCLIエディタを使いつつ、GUIが必要な場面や、より視覚的な操作が適している場面でSublime Textを併用しています。つまり、「メインのIDE」として使うのではなく、職人的な開発者の道具箱の中の1つとして位置づけられているのです。&lt;&#x2F;p&gt;
&lt;p&gt;VS Codeのような統合開発環境とは、もはや直接競争する立場にありません。機能の豊富さや拡張性では勝負せず、「軽快さ」「シンプルさ」「信頼性」という独自の価値を提供し続けることで、固有のポジションを確立しています。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;4._ビジネスモデル&quot;&gt;4. ビジネスモデル&lt;&#x2F;h2&gt;
&lt;p&gt;Sublime Textが長期にわたって開発を継続できているのは、独自のビジネスモデルによるところが大きいです。多くのソフトウェアが無料化やサブスクリプションモデルに移行する中、Sublime Textは独自の道を歩んでいます。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;4.1._買い切り型ライセンス_+_更新権&quot;&gt;4.1. 買い切り型ライセンス + 更新権&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;一度購入すれば永続的に使用可能&lt;&#x2F;li&gt;
&lt;li&gt;購入時点から &lt;strong&gt;約3年間のアップデート権&lt;&#x2F;strong&gt; が付与される&lt;&#x2F;li&gt;
&lt;li&gt;更新権が切れても使用不可にはならない&lt;&#x2F;li&gt;
&lt;li&gt;新しいメジャー版や最新ビルドを使いたい場合のみ再購入&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Sublime Textのライセンスは、買い切り型を基本としています。一度購入すれば、そのバージョンは永続的に使用可能です。ただし、購入時点から約3年間のアップデート権が付与され、その期間内にリリースされた新バージョンには無料でアップグレードできます。&lt;&#x2F;p&gt;
&lt;p&gt;重要なのは、更新権が切れても、ソフトウェアが使用不可になることはない点です。購入時のバージョンは引き続き使用でき、セキュリティアップデートなどの重要な修正も提供されます。新しいメジャーバージョンや最新機能を使いたい場合にのみ、ライセンスを再購入すればよいのです。&lt;&#x2F;p&gt;
&lt;p&gt;このモデルは、月額・年額で支払い続けなければ使えなくなるSaaS的なサブスクリプションとは明確に異なります。ユーザーは「払い続けなければ使えなくなる」というプレッシャーから解放され、自分のペースでアップグレードを判断できます。一方で、開発側も定期的な収入が見込めるため、持続可能な開発が可能になっています。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;4.2._非_SaaS・低固定費構造&quot;&gt;4.2. 非 SaaS・低固定費構造&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;クラウドサービスではない&lt;&#x2F;li&gt;
&lt;li&gt;常時稼働サーバや大規模インフラが不要&lt;&#x2F;li&gt;
&lt;li&gt;開発チームは少人数&lt;&#x2F;li&gt;
&lt;li&gt;営業・マーケティングコストが極小&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Sublime Textのもう1つの強みは、極めて低い固定費構造にあります。Sublime Textはクラウドサービスではなく、ユーザーのローカル環境で完結するスタンドアロンアプリケーションです。そのため、常時稼働するサーバーインフラや、大規模なデータセンターといった継続的なコストが一切発生しません。&lt;&#x2F;p&gt;
&lt;p&gt;開発チームも非常に小規模で、創設者のJon Skinner氏を中心とした数名程度で運営されていると言われています。大規模な開発組織を抱える必要がなく、人件費も抑えられています。&lt;&#x2F;p&gt;
&lt;p&gt;また、営業やマーケティングにも積極的に投資していません。広告を出すこともなく、口コミとブランド力だけで販売を続けています。Sublime Textの公式サイトは極めてシンプルで、派手なマーケティングメッセージもありません。&lt;&#x2F;p&gt;
&lt;p&gt;この結果、&lt;strong&gt;ユーザー数が爆発的に増えなくても黒字が成立する&lt;&#x2F;strong&gt;構造になっています。年間数万人程度のライセンス購入があれば、十分に開発を継続できるのです。これは、成長至上主義に陥らず、持続可能な開発を可能にする重要な要素となっています。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;4.3._法人・プロユーザーによる支え&quot;&gt;4.3. 法人・プロユーザーによる支え&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;個人購入に加え、法人でのまとめ買い&lt;&#x2F;li&gt;
&lt;li&gt;経費精算による定期的な更新&lt;&#x2F;li&gt;
&lt;li&gt;長期利用を前提としたユーザー層&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Sublime Textのユーザーには、個人利用だけでなく、法人でのまとめ買いも多いと考えられます。開発チームが一斉にライセンスを購入するケースや、企業の標準ツールとして採用されているケースもあります。特に、パフォーマンスや安定性を重視する企業にとって、Sublime Textは魅力的な選択肢となります。&lt;&#x2F;p&gt;
&lt;p&gt;また、プロフェッショナルな開発者が多いため、ライセンスを経費として精算し、定期的に更新する傾向があります。個人で$99を支払うのは躊躇するかもしれませんが、会社の経費であれば、更新のハードルは下がります。&lt;&#x2F;p&gt;
&lt;p&gt;Sublime Textのユーザーは、長期利用を前提としている傾向が強いです。一度使い始めたら、数年から十年以上にわたって使い続けるユーザーが多いのです。これは、Sublime Textの安定性とシンプルさが、長期的な信頼を生んでいることを示しています。&lt;&#x2F;p&gt;
&lt;p&gt;一人あたりのLTV（顧客生涯価値）は、サブスクリプションモデルと比べると低めですが、非常に安定しています。ユーザーの離脱率が低く、定期的な更新が見込めるため、予測可能な収益構造となっているのです。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;4.4._成長を前提としない経営姿勢&quot;&gt;4.4. 成長を前提としない経営姿勢&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;ベンチャーキャピタルに依存しない&lt;&#x2F;li&gt;
&lt;li&gt;利用データの収集・広告モデルなし&lt;&#x2F;li&gt;
&lt;li&gt;ユーザー数や市場シェアの拡大を至上命題としない&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Sublime Textの最も特徴的な点は、成長を前提としない経営姿勢にあります。ベンチャーキャピタルからの資金調達を受けておらず、外部投資家からの「成長しろ」というプレッシャーとは無縁です。そのため、ユーザー数を爆発的に増やすことや、市場シェアを最大化することを目標とする必要がありません。&lt;&#x2F;p&gt;
&lt;p&gt;また、ユーザーの利用データを収集して分析したり、広告モデルで収益化したりといったことも一切行っていません。Sublime Textは、インターネット接続を必要とせず、ローカル環境で完結するため、プライバシーの観点でも安心できます。テレメトリデータの送信もなく、ユーザーがどのような使い方をしているかは開発者にはわかりません。&lt;&#x2F;p&gt;
&lt;p&gt;この経営姿勢は、現代のスタートアップ文化やシリコンバレーの常識とは真逆です。「急成長」「ユニコーン」「市場の独占」といった価値観とは距離を置き、その代わりに**「小さく、長く、静かに続ける」**ことを選択しています。&lt;&#x2F;p&gt;
&lt;p&gt;これは、短期的な利益最大化ではなく、長期的な持続可能性を重視した結果です。派手さはありませんが、10年後、20年後も同じように開発が続いている。そんな可能性を信じさせてくれるのが、Sublime Textなのです。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;5._Sublime_Merge_-_同じ思想の_Git_クライアント&quot;&gt;5. Sublime Merge - 同じ思想の Git クライアント&lt;&#x2F;h2&gt;
&lt;p&gt;Sublime HQは、テキストエディタのSublime Textだけでなく、Gitクライアントの &lt;strong&gt;Sublime Merge&lt;&#x2F;strong&gt; も開発しています。Sublime Mergeは、Sublime Textと同じ設計思想をGitクライアントに適用したソフトウェアです。&lt;&#x2F;p&gt;
&lt;p&gt;Sublime Mergeの特徴も、Sublime Textと共通しています。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;起動が非常に速く、大規模リポジトリでも軽快に動作する&lt;&#x2F;li&gt;
&lt;li&gt;UIがシンプルで、視覚的なノイズが少ない&lt;&#x2F;li&gt;
&lt;li&gt;複雑なGit操作も、キーボード中心の操作で素早く実行できる&lt;&#x2F;li&gt;
&lt;li&gt;独自のマージツールが優れており、コンフリクト解決が快適&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Gitクライアントの世界でも、GitKrakenやSourceTreeといった多機能なGUIツールが主流となっていますが、Sublime Mergeはそれらとは異なるアプローチを取っています。必要な機能に絞り込み、パフォーマンスと操作性を優先した結果、Gitの複雑な操作を快適に行えるツールとなっています。&lt;&#x2F;p&gt;
&lt;p&gt;ビジネスモデルもSublime Textと同様で、買い切り型ライセンス + 約3年間の更新権という形式です。Sublime TextとSublime Mergeをセットで購入すると割引が適用されるバンドルライセンスも提供されています。&lt;&#x2F;p&gt;
&lt;p&gt;私自身も、Sublime Textの思想に共鳴し、今回Sublime Textのライセンスを更新すると同時に、Sublime Mergeのライセンスも購入しました。どちらも、長く使い続けられる信頼できるツールだと感じています。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;6._評価と総括&quot;&gt;6. 評価と総括&lt;&#x2F;h2&gt;
&lt;p&gt;Sublime Textは次のようなソフトウェアです。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;主役ではなくなったが、品質は今も一級品&lt;&#x2F;li&gt;
&lt;li&gt;時代の要請すべてには応えないが、軸はぶれない&lt;&#x2F;li&gt;
&lt;li&gt;利便性よりも、編集体験の純度を重視&lt;&#x2F;li&gt;
&lt;li&gt;商業的成功よりも、持続可能性を優先&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;その結果として、&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;「勢いはないが、消えもしない」&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;という独特のポジションを確立しています。&lt;&#x2F;p&gt;
&lt;p&gt;現代のソフトウェア業界では、「より多くの機能」「より大きなエコシステム」「より速い成長」が正義とされがちです。しかし、Sublime Textはそれとは異なる価値観を示しています。機能を抑制し、シンプルさを保ち、持続可能な開発を優先することで、長期的な信頼を獲得しているのです。&lt;&#x2F;p&gt;
&lt;p&gt;このアプローチは、すべてのソフトウェアに適用できるわけではありません。しかし、少なくとも「開発ツール」という領域においては、十分に成立する戦略であることを、Sublime Textは証明しています。&lt;&#x2F;p&gt;
&lt;p&gt;Sublime Textは、現代では稀少になった&lt;strong&gt;職人主義的ソフトウェアと、そのビジネスモデルの実例&lt;&#x2F;strong&gt;です。派手さはありませんが、確かな品質と一貫した思想を持ち続けることで、静かに、しかし確実に生き残っているのです。&lt;&#x2F;p&gt;
</content>
        <summary type="html">高速性と簡潔さを追求し続けるテキストエディタSublime Text。
VS Codeに市場シェアを奪われても品質を保ち続ける職人主義的な
設計思想と、サブスクリプションに依存しないワンタイム購入モデルの
持続可能性について考察します。
</summary>
        </entry><entry xml:lang="en">
        <title>スキャンPDFの処理を自動化するClaude Codeプラグインを作った</title>
        <published>2026-01-02T00:00:00+00:00</published>
        <updated>2026-01-02T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2026/01/pdf-processor-plugin/" type="text/html"/>
        <id>https://codedchords.dev/blog/2026/01/pdf-processor-plugin/</id>
        
            <content type="html">&lt;h2 id=&quot;はじめに&quot;&gt;はじめに&lt;&#x2F;h2&gt;
&lt;p&gt;書籍をスキャナーで読み取ってPDF化すると、複数のファイルに分かれてしまったり、テキスト検索ができなかったりします。また、目次がないため、そのままでは使いにくい状態になります。これらを手作業で処理するのは非常に面倒です。&lt;&#x2F;p&gt;
&lt;p&gt;そこで、スキャンしたPDFの処理を自動化するClaude Codeプラグイン「pdf-processor」を開発しました。このプラグインを使えば、複数のPDFファイルのマージ、OCR処理、目次の追加を簡単に実行でます。&lt;&#x2F;p&gt;
&lt;p&gt;プラグインのソースコードは&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;yostos&#x2F;claude-code-plugins&#x2F;tree&#x2F;main&#x2F;plugins&#x2F;pdf-processor&quot;&gt;GitHub&lt;&#x2F;a&gt;で公開しています。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;pdf-processorプラグインの機能&quot;&gt;pdf-processorプラグインの機能&lt;&#x2F;h2&gt;
&lt;p&gt;このプラグインは、スキャンされたPDFファイルを実用的なデジタル書籍に変換するためのツールです。主な機能は以下の通りです。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;複数PDFファイルのマージ&lt;&#x2F;strong&gt;: バラバラのPDFファイルを1つに統合&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;OCR処理&lt;&#x2F;strong&gt;: 日本語に対応したOCR処理により、画像PDFをテキスト検索可能に変換&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;ファイルサイズ最適化&lt;&#x2F;strong&gt;: 画像の圧縮により、ファイルサイズを削減&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;目次（ブックマーク）の追加&lt;&#x2F;strong&gt;: PDFビューアで使える目次を自動生成&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;メタデータ編集&lt;&#x2F;strong&gt;: PDFのタイトル、著者などのメタデータを設定&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;使い方&quot;&gt;使い方&lt;&#x2F;h2&gt;
&lt;p&gt;pdf-processorプラグインは、3つのステップで処理を行います。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;ステップ1:_前処理の実行&quot;&gt;ステップ1: 前処理の実行&lt;&#x2F;h3&gt;
&lt;p&gt;まず、&lt;code&gt;&#x2F;pdf-processor:preprocess&lt;&#x2F;code&gt; コマンドを実行して、複数のPDFファイルをマージし、OCR処理を行います。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;pdf-processor:preprocess&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Claudeが以下の処理を自動で実行します。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;対象となるPDFファイルの確認&lt;&#x2F;li&gt;
&lt;li&gt;PDFのマージ&lt;&#x2F;li&gt;
&lt;li&gt;OCR処理の実行&lt;&#x2F;li&gt;
&lt;li&gt;画像の最適化&lt;&#x2F;li&gt;
&lt;li&gt;目次テンプレートファイルの生成&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;処理が完了すると、OCR処理済みのPDFファイルと、メタデータをダンプしたファイルが生成されます。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;ステップ2:_目次情報の編集&quot;&gt;ステップ2: 目次情報の編集&lt;&#x2F;h3&gt;
&lt;p&gt;ダンプされたメタデータファイルをエディタで開き、目次情報を追加します。目次は以下の形式で記述します。&lt;&#x2F;p&gt;
&lt;p&gt;各目次項目は &lt;code&gt;BookmarkBegin&lt;&#x2F;code&gt; で始まり、以下の3つのフィールドで構成されます。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;BookmarkTitle&lt;&#x2F;code&gt;: 目次のタイトル（章名など）&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;BookmarkLevel&lt;&#x2F;code&gt;: 目次の階層レベル（1が最上位、2が第2階層）&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;BookmarkPageNumber&lt;&#x2F;code&gt;: 目次項目が指すページ番号&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;例として、以下のように追加します。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;BookmarkBegin&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;BookmarkTitle: 第1章 はじめに&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;BookmarkLevel: 1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;BookmarkPageNumber: 1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;BookmarkBegin&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;BookmarkTitle: 1.1 背景&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;BookmarkLevel: 2&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;BookmarkPageNumber: 2&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;BookmarkBegin&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;BookmarkTitle: 1.2 目的&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;BookmarkLevel: 2&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;BookmarkPageNumber: 5&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;BookmarkBegin&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;BookmarkTitle: 第2章 実装&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;BookmarkLevel: 1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;BookmarkPageNumber: 10&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;ステップ3:_目次の適用&quot;&gt;ステップ3: 目次の適用&lt;&#x2F;h3&gt;
&lt;p&gt;目次情報を編集したら、&lt;code&gt;&#x2F;pdf-processor:apply-toc&lt;&#x2F;code&gt; コマンドを実行して、最終的なPDFファイルを生成します。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;pdf-processor:apply-toc&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;このコマンドを実行すると、OCR処理済みのPDFに目次が追加され、完成版のPDFファイルが作成されます。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;技術的な詳細&quot;&gt;技術的な詳細&lt;&#x2F;h2&gt;
&lt;p&gt;pdf-processorプラグインは、以下のツールを組み合わせて実装しています。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;OCRmyPDF&lt;&#x2F;strong&gt;: PythonベースのOCRツールで、Tesseract OCRエンジンを使用してPDFにテキストレイヤーを追加&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;PDFtk&lt;&#x2F;strong&gt;: PDFの操作に特化したコマンドラインツールで、マージやメタデータの編集に使用&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Ghostscript&lt;&#x2F;strong&gt;: PDFの最適化と圧縮に使用&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;これらのツールのインストールや設定は、プラグインのREADMEに詳しく記載されています。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;まとめ&quot;&gt;まとめ&lt;&#x2F;h2&gt;
&lt;p&gt;pdf-processorプラグインを使うことで、スキャンしたPDFの処理を大幅に効率化できます。複数ファイルのマージ、OCR処理、目次の追加といった面倒な作業を、Claude Codeとの対話だけで完了できるようになりました。&lt;&#x2F;p&gt;
&lt;p&gt;スキャンした書籍や資料をデジタル化する際に、ぜひ活用してみてください。プラグインのソースコードは&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;yostos&#x2F;claude-code-plugins&#x2F;tree&#x2F;main&#x2F;plugins&#x2F;pdf-processor&quot;&gt;GitHub&lt;&#x2F;a&gt;で公開しているので、カスタマイズや改善の提案も歓迎します。&lt;&#x2F;p&gt;
</content>
        <summary type="html">書籍をスキャナーで読み取ってPDF化した後の処理を簡単にするため、
Claude Codeプラグイン「pdf-processor」を開発しました。
複数PDFのマージ、OCR処理、ファイルサイズ最適化、目次の追加を
自動化し、スキャン書籍を実用的なデジタル書籍に変換します。
</summary>
        </entry><entry xml:lang="en">
        <title>MAGIシステムをClaude Code Pluginで実装してみた</title>
        <published>2025-12-12T00:00:00+00:00</published>
        <updated>2025-12-12T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2025/12/magi-claude-code-plugin/" type="text/html"/>
        <id>https://codedchords.dev/blog/2025/12/magi-claude-code-plugin/</id>
        
            <content type="html">&lt;details&gt;
&lt;summary&gt;Table of Contents&lt;&#x2F;summary&gt;
  &lt;!-- toc --&gt;
&lt;&#x2F;details&gt;
&lt;h2 id=&quot;Claude_Code_Pluginとは&quot;&gt;Claude Code Pluginとは&lt;&#x2F;h2&gt;
&lt;p&gt;Claude Code Pluginは、AnthropicのClaude Code CLI向けの拡張機能システムです。プラグインを使用することで、Claudeに新しいコマンド、エージェント、スキル、フックなどを追加できます。&lt;&#x2F;p&gt;
&lt;p&gt;主な機能は以下の通りです。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;スラッシュコマンド&lt;&#x2F;strong&gt;: 独自のコマンドを定義してClaude Codeから実行&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;カスタムエージェント&lt;&#x2F;strong&gt;: 特定のタスクに特化したAIエージェントを作成&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;スキル&lt;&#x2F;strong&gt;: 再利用可能な機能をスキルとして定義&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;フック&lt;&#x2F;strong&gt;: ツール実行前後などのイベントに対応したアクションを定義&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;MCP統合&lt;&#x2F;strong&gt;: Model Context Protocol経由で外部サービスと連携&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;プラグインはマーケットプレイスから簡単にインストールでき、ローカルでの開発も可能です。これにより、チームやプロジェクトごとにClaude Codeの機能をカスタマイズできます。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;エヴァンゲリオンのMAGIシステムとは&quot;&gt;エヴァンゲリオンのMAGIシステムとは&lt;&#x2F;h2&gt;
&lt;p&gt;MAGIは、アニメ「新世紀エヴァンゲリオン」に登場する架空のスーパーコンピュータシステムです。人間の頭脳をベースにした3つの独立したシステムで構成されており、重要な意思決定を合議制で行います。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;MAGIの3つのシステム&quot;&gt;MAGIの3つのシステム&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;MELCHIOR（メルキオール）&lt;&#x2F;strong&gt;: 科学者としての側面を模擬。論理性と合理性に基づいて判断する&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;BALTHASAR（バルタザール）&lt;&#x2F;strong&gt;: 母親としての側面を模擬。保護と倫理を重視して判断する&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;CASPER（キャスパー）&lt;&#x2F;strong&gt;: 女性としての側面を模擬。感情と共感に基づいて判断する&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;この3つのシステムは、それぞれ異なる視点から問題を分析し、多数決で最終的な結論を導きます。人間の多面的な判断プロセスを再現することで、より包括的で偏りの少ない意思決定を目指しています。&lt;&#x2F;p&gt;
&lt;p&gt;作中では、「使徒」への対処方法など、人類の存続に関わる重要な判断をMAGIにより下される場面が描かれています。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;Magi_Claude_Code_Pluginの実装&quot;&gt;Magi Claude Code Pluginの実装&lt;&#x2F;h2&gt;
&lt;p&gt;このコンセプトを実際のシステムとして実装したのが、今回作成した「Magi」Claude Code Pluginです。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;システム構成&quot;&gt;システム構成&lt;&#x2F;h3&gt;
&lt;p&gt;Magiシステムは4つのエージェントで構成されています。&lt;&#x2F;p&gt;


&lt;noscript&gt;
    &lt;strong&gt;⚠️ JavaScript is required to render the diagram.&lt;&#x2F;strong&gt;
&lt;&#x2F;noscript&gt;
&lt;pre class=&quot;mermaid invertible-image&quot;&gt;
    flowchart LR
   U[fa:fa-user User]
    subgraph magi
      A[ARBITRATOR]
      B[MELCHIOR]
      C[BALTHASAR]
      D[CASPER]
    end
 
    U --&gt;|1.request| A
    A --&gt;|2.reconcile| U
    A --&gt;B
    A --&gt;C
    A --&gt;D
    A ---&gt;|5.result|U
&lt;&#x2F;pre&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Agent&lt;&#x2F;th&gt;&lt;th&gt;Role&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;ARBITRATOR（アービトレーター）&lt;&#x2F;td&gt;&lt;td&gt;課題の構造化と最終調停を担当&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;MELCHIOR（メルキオール）&lt;&#x2F;td&gt;&lt;td&gt;科学的・技術的な分析を担当&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;BALTHASAR（バルタザール）&lt;&#x2F;td&gt;&lt;td&gt;法律的・倫理的な分析を担当&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;CASPER（キャスパー）&lt;&#x2F;td&gt;&lt;td&gt;感情的・トレンド分析を担当&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;h3 id=&quot;動作フロー&quot;&gt;動作フロー&lt;&#x2F;h3&gt;
&lt;p&gt;システムの動作は3つのフェーズに分かれています。&lt;&#x2F;p&gt;
&lt;dl&gt;
  &lt;dt&gt;Phase 1: 課題の構造化。&lt;&#x2F;dt&gt;
  &lt;dd&gt;
    ARBITRATORがユーザーとの対話を通じて、漠然とした課題を命題、前提、A案、B案の形式に整理します。この構造化により、エージェントたちが同じ前提で議論できるようになります。
  &lt;&#x2F;dd&gt;
  &lt;dt&gt;Phase 2: 並列分析。&lt;&#x2F;dt&gt;
  &lt;dd&gt;
    3つの専門エージェントが同時並行で分析を開始します。
    重要なのは、各エージェントが**完全に独立して判断する**点です。他のエージェントの意見を参照せず、自身の専門性と価値観に基づいて結論を出します。
    各エージェントはWeb検索機能を使って最新の情報を収集し、その結果を判断の根拠として提示します。
  &lt;&#x2F;dd&gt;
  &lt;dt&gt;Phase 3: 合議と結論。&lt;&#x2F;dt&gt;
  &lt;dd&gt;
    ARBITRATORが3つのエージェントの投票結果を集計し、多数決で最終結論を決定します。
  &lt;&#x2F;dd&gt;
&lt;&#x2F;dl&gt;
&lt;h2 id=&quot;インストール方法&quot;&gt;インストール方法&lt;&#x2F;h2&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;git&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; clone https:&#x2F;&#x2F;github.com&#x2F;yostos&#x2F;claude-code-plugins.git&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-function z-builtin&quot;&gt;cd&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; claude-code-plugins&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;claude&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# claude code上で&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;&#x2F;plugin&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; marketplace add &#x2F;path&#x2F;to&#x2F;claude-code-plugins&#x2F;marketplace test-marketplace&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;&#x2F;plugin&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; install magi@test-marketplace&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;プラグインを有効化するため、Claude Codeを一度終了して再起動します。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;実際の使用例&quot;&gt;実際の使用例&lt;&#x2F;h2&gt;
&lt;p&gt;実際の使用例です。設問は次の通りです。&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;東京湾から上陸した巨大怪獣を自衛隊がディズニーランドで撃退したとします。ディズニーランドには巨大怪獣の遺体が残り、オ
リエンタルランドはディズニーランド営業再開のため一刻も早く片付けを希望しています。しかし、片付けには膨大な費用が必要です。さて、この片付け費用が誰が払うべきでしょうか?&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;この設問をARBITRATORが次のように整理してくれました。&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;dl&gt;
  &lt;dt&gt;命題。&lt;&#x2F;dt&gt;
  &lt;dd&gt;巨大怪獣の遺体撤去費用は誰が負担すべきか。&lt;&#x2F;dd&gt;
  &lt;dt&gt;前提。&lt;&#x2F;dt&gt;
  &lt;dd&gt;
    &lt;ul&gt;
      &lt;li&gt;自衛隊が国防行動として怪獣を撃退した。&lt;&#x2F;li&gt;
      &lt;li&gt;撤去には膨大な費用（数億～数十億円規模と想定）が必要。&lt;&#x2F;li&gt;
      &lt;li&gt;オリエンタルランドは早急な営業再開を望んでいる。&lt;&#x2F;li&gt;
      &lt;li&gt;遺体はオリエンタルランドの施設・敷地内に存在する。&lt;&#x2F;li&gt;
      &lt;li&gt;類似の法的前例は存在しない。&lt;&#x2F;li&gt;
      &lt;li&gt;保険適用は絶望的（前代未聞の事態のため）。&lt;&#x2F;li&gt;
      &lt;li&gt;災害対策基本法の適用可否については賛否が分かれている。&lt;&#x2F;li&gt;
    &lt;&#x2F;ul&gt;
  &lt;&#x2F;dd&gt;
  &lt;dt&gt;A案: 国（政府）が全額負担。&lt;&#x2F;dt&gt;
  &lt;dd&gt;
    理由は、自衛隊による国防行動の結果であり、公共の安全確保のための公的措置。国民全体の利益のために行った行動の結果責任。
  &lt;&#x2F;dd&gt;
  &lt;dt&gt;B案: オリエンタルランド（施設所有者）が全額負担。&lt;&#x2F;dt&gt;
  &lt;dd&gt;
    理由は、自社敷地内に存在する物件の管理責任。営業再開による利益は企業が享受するため、その前提となる費用も負担すべき。
  &lt;&#x2F;dd&gt;
&lt;&#x2F;dl&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;最終的な3つのAIエージェントの投票結果は次のようなものでした。
それぞれの観点からの合理性が述べられており、根拠も明確です。これは意外に活用できそうです。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;【MAGI システム 最終結論】&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;投票結果: A案 3票 vs B案 0票&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;採択: A案（国が全額負担）&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;---&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;各エージェントの判断:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;MELCHIOR (科学的・技術的分析): A案&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;- 因果関係の明確性: 遺体発生の直接原因は国の防衛行動&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;- 費用構造の特殊性: 通常の事業リスクの範囲を遥かに超える規模と技術的複雑性&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;- 経済効率性: 社会全体での負担分散が最適（総合スコア A案 4.75 vs B案 2.25）&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;- リスク配分の合理性: 企業に制御不可能なリスクを負わせることは非合理的&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;BALTHASAR (法律・倫理的分析): A案&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;- 法的根拠: 自衛隊法に基づく国防行動の結果責任、災害対策基本法の類推適用可能性&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;- 憲法的視点: 憲法第29条（財産権保障）の趣旨から、公共目的のための損失は補償されるべき&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;- 倫理的公正: 予見不可能な災厄の費用を偶然性で一企業に負担させることは著しく不公正&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;- 社会的連帯: リスクを全納税者に薄く広く分散することが社会正義に適う&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;CASPER (感情・トレンド分析): A案&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;- 感情的公正: 被害者をさらに苦しめる構図は国民感情として受け入れがたい&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;- 雇用への配慮: 数万人の従業員と家族、地域経済への深刻な影響を回避&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;- 現代的価値観: 人間中心、包摂的な危機管理が現代社会のトレンド&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;- 社会的連帯: 「国を守るために国が行った行動の結果は国民全体で支える」という温かい選択&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;---&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;結論の要約:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;全会一致でA案が採択されました。 これは極めて強い合意です。&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;巨大怪獣の遺体撤去費用は、国（政府）が全額負担すべきです。&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;主要な論点:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;1. 因果関係: 遺体が発生したのは、国の防衛行動の直接的結果である&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;2. 予見可能性: 怪獣襲来は通常の事業リスク評価の範囲外であり、企業に予見・対策を求めることは不可能&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;3. 法的整合性: 災害対策基本法の類推適用、憲法第29条の財産権保障、国家責任の原則から、国が負担すべき&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;4. 経済合理性: 社会全体で負担を分散することで、企業倒産リスクを回避し、経済的ショックを最小化できる&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;5. 倫理的公正: たまたま被害を受けた場所の所有者だけに負担させることは、偶然性に基づく不正義である&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;6. 社会的連帯: 国防の便益は国民全体が享受したのだから、その費用も国民全体で負担すべき&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;7. 雇用と地域経済: 数万人の従業員とその家族、周辺地域への影響を考慮すべき&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;8. 将来への影響: 人間中心の危機管理の前例として、未来の類似事態への柔軟な対応を可能にする&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;---&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;推奨される具体的措置:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;1. 特別措置法の制定: 「巨大生物災害対策特別措置法」等を制定し、法的根拠を明確化&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;2. 予備費・補正予算の活用: 迅速な費用確保と撤去作業の開始&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;3. 自衛隊・専門機関の協力: 技術的リソースの効率的活用&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;4. 将来の類似事態への備え: 法的・技術的フレームワークの整備&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;---&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;参照情報:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;MELCHIOR (科学的・技術的):&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;- 分析手法: ISO 31000リスクマネジメント、公共財理論、費用便益分析(CBA)、システム工学的因果分析&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;- 技術的考慮: 生物学的ハザード管理、特殊装備の必要性、撤去費用構造の推定&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;BALTHASAR (法律・倫理的):&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;- 関連法令:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  自衛隊法第3条、国家賠償法第1条、災害対策基本法第2条・第87条、憲法第29条第3項、民法第242条・第709条・第717条&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;- 法原則: 国家責任の原則、社会的公正と衡平の原則、過失責任主義、公共の利益優先の原則、損失補償の法理&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;CASPER (感情・トレンド):&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;- 社会的トレンド: 公共安全への公的責任の重視、被害者への共感文化、雇用保護への関心、前例のない危機への柔軟対応&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;- 感情的考慮: 数万人の従業員と家族への影響、年間数千万人の来場者、地域経済、社会的連帯の精神&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;---&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;MAGIシステムの最終判定として、国（政府）が全額負担することを強く推奨します。&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;技術的な特徴&quot;&gt;技術的な特徴&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;エージェントの独立性&quot;&gt;エージェントの独立性&lt;&#x2F;h3&gt;
&lt;p&gt;各エージェントは完全に独立して動作します。バックグラウンドで並列実行され、他のエージェントの分析結果を参照することはありません。これにより、以下のメリットがあります。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;多様な視点の確保&lt;&#x2F;li&gt;
&lt;li&gt;偏りの少ない意思決定&lt;&#x2F;li&gt;
&lt;li&gt;各専門分野の独立した評価&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;情報収集能力&quot;&gt;情報収集能力&lt;&#x2F;h3&gt;
&lt;p&gt;各エージェントはWeb検索機能を使って最新の情報を収集します。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;MELCHIOR: 技術動向、ベンチマークデータ、研究論文など&lt;&#x2F;li&gt;
&lt;li&gt;BALTHASAR: 法律、規制、判例、ガイドラインなど&lt;&#x2F;li&gt;
&lt;li&gt;CASPER: トレンドレポート、ユーザーレビュー、事例研究など&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;収集した情報は判断の根拠として明示されるため、透明性の高い意思決定プロセスが実現できます。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;セッション管理&quot;&gt;セッション管理&lt;&#x2F;h3&gt;
&lt;p&gt;オプションで &lt;code&gt;state.json&lt;&#x2F;code&gt; にセッション状態を保存できます。これにより、分析を中断・再開できます。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;まとめ&quot;&gt;まとめ&lt;&#x2F;h2&gt;
&lt;p&gt;MAGIシステムは、エヴァンゲリオンの架空のシステムを実際のAI技術で再現した興味深い試みです。複数の専門的な視点から独立して分析し、合議制で結論を導くアプローチは、以下のような場面で有用です。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;重要なビジネス判断&lt;&#x2F;li&gt;
&lt;li&gt;技術選定&lt;&#x2F;li&gt;
&lt;li&gt;組織的な意思決定&lt;&#x2F;li&gt;
&lt;li&gt;倫理的な判断を伴う課題&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Claude Code Pluginの仕組みを活用することで、このような複雑なマルチエージェントシステムを比較的容易に実装できることがわかりました。&lt;&#x2F;p&gt;
&lt;p&gt;プラグインのソースコードは&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;yostos&#x2F;claude-code-plugins&quot;&gt;GitHubリポジトリ&lt;&#x2F;a&gt;で公開しています。興味のある方はぜひ試してみてください。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;参考資料&quot;&gt;参考資料&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;docs.anthropic.com&#x2F;claude&#x2F;docs&#x2F;claude-code&quot;&gt;Claude Code Plugin Documentation&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;yostos&#x2F;claude-code-plugins&quot;&gt;Magi Plugin Repository&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;ja.wikipedia.org&#x2F;wiki&#x2F;%E6%96%B0%E4%B8%96%E7%B4%80%E3%82%A8%E3%83%B4%E3%82%A1%E3%83%B3%E3%82%B2%E3%83%AA%E3%82%AA%E3%83%B3&quot;&gt;新世紀エヴァンゲリオン&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</content>
        <summary type="html">エヴァンゲリオンに登場するMAGIシステムを参考に、複数の専門AIエージェントによる合議制意思決定支援システムをClaude Code Pluginとして実装しました。MELCHIOR、BALTHASAR、CASPERの3つのエージェントが、科学的、法律的、感情的な視点から独立して分析を行い、多数決で結論を導くシステムです。</summary>
        </entry><entry xml:lang="en">
        <title>Anthropic Interviewer</title>
        <published>2025-12-07T00:00:00+00:00</published>
        <updated>2025-12-07T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2025/12/anthropic-interviewer/" type="text/html"/>
        <id>https://codedchords.dev/blog/2025/12/anthropic-interviewer/</id>
        
            <content type="html">&lt;h2 id=&quot;Anthropic_Interviewerとは&quot;&gt;Anthropic Interviewerとは&lt;&#x2F;h2&gt;
&lt;p&gt;AnthropicはClaudeの使用パターンを分析するツール「Clio」を利用して生成AIの利用パターン
などを調査してきました。しかしClioで分かるのは、Claude内で何が起きているかだけで、
Claudeがどう外の世界に影響しているかは分析できていませんでした。&lt;&#x2F;p&gt;
&lt;p&gt;ユーザーはClaudeの出力をどう使っているのか？　AIについてどう感じているのか？
これを知るには、Claudeの入出力から分析できず、ユーザーに直接聞くしかありません。&lt;&#x2F;p&gt;
&lt;p&gt;そこでAnthropicは、Claude自身がインタビュアーとなる「Anthropic Interviewer」を開発したということです。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;参加方法&quot;&gt;参加方法&lt;&#x2F;h2&gt;
&lt;p&gt;Anthropic Interviewerは、Claude.aiのFree、Pro、Maxサブスクライバー（登録から2週間以上経過）が対象です。
Claude.ai上でポップアップ招待が表示されるか、直接 &lt;code&gt;claude.ai&#x2F;interviewer&lt;&#x2F;code&gt; にアクセスすることで参加できます。&lt;&#x2F;p&gt;
&lt;p&gt;インタビューは約10〜15分で、回答に応じて質問が適応的に変化するリアルタイム会話形式です。
具体的な質問内容は固定されておらず、以下のテーマを探索します。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;AIの将来的な役割についてのビジョン&lt;&#x2F;li&gt;
&lt;li&gt;その視点を形成する経験、価値観、ニーズ&lt;&#x2F;li&gt;
&lt;li&gt;そのビジョンを助ける、または妨げる要因&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;初期テストでは、参加者の97.6%が満足度5以上（7段階評価）と回答し、99.12%が他者に推奨すると答えています。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;現在のインタビュー結果&quot;&gt;現在のインタビュー結果&lt;&#x2F;h2&gt;
&lt;p&gt;このツールを使って、1,250人にインタビューした結果が、
すでに「&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.anthropic.com&#x2F;research&#x2F;anthropic-interviewer&quot;&gt;Introducing Anthropic Interviewer: What 1,250 professionals told us about working with AI&lt;&#x2F;a&gt;」
という記事で公開されています。&lt;&#x2F;p&gt;
&lt;p&gt;この記事によると、このツールを使って、一般労働者1,000人、科学者125人、クリエイター125人の計
1,250人の専門家にインタビューを実施し、AIの使用実態や感情を調査したそうです。&lt;&#x2F;p&gt;
&lt;p&gt;結果として、全体的には楽観的な見方が優勢でした。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;一般労働者の86%が時間節約を実感し、日常的な作業をAIに委任しつつ、専門的アイデンティティを定義する業務は自分で行いたいと考えている&lt;&#x2F;li&gt;
&lt;li&gt;クリエイターは97%が時間節約を報告しているが、仲間からの偏見や経済的置き換えへの不安も抱えている&lt;&#x2F;li&gt;
&lt;li&gt;科学者は論文執筆やコードのデバッグにAIを活用しているが、仮説生成や実験設計などの中核的研究には信頼性の問題からまだ使用を限定している&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;私の生成AI感&quot;&gt;私の生成AI感&lt;&#x2F;h2&gt;
&lt;p&gt;今回15分ほどのインタビューを受けて、改めて自身の生成AIに対する向き合い方を意識できました。&lt;&#x2F;p&gt;
&lt;p&gt;意外だったのは、AIにServant的な役割を期待していないということです。
もちろん、生成AIに作業を代行させて生産性を上げるということはやっていますが、
あまりそこを重視していません。
それどころか、AIロボットのような人間の召使い的な方向で発展するのを極端に嫌悪しているのを初めて自分でも意識しました。&lt;&#x2F;p&gt;
&lt;p&gt;最も活用できる方向として、自分と同等以上の知識と論理性を持った「ディスカッション相手」としての生成AIだと意識できました。
自分を生成AIとの会話から新しいアイデアに辿り着いた体験が何度かあり、それが一番衝撃的だったので影響されているのだと思います。&lt;&#x2F;p&gt;
&lt;p&gt;人間にDVを受けるロボットより、バベルの塔のマザーコンピューター&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-1-1&quot;&gt;&lt;a href=&quot;#fn-1&quot;&gt;1&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;を見たいのです。&lt;&#x2F;p&gt;
&lt;section class=&quot;footnotes&quot;&gt;
&lt;ol class=&quot;footnotes-list&quot;&gt;
&lt;li id=&quot;fn-1&quot;&gt;
&lt;p&gt;『バビル2世』に登場するコンピューターです。5000年前、地球に不時着した宇宙人「バビル1世」が建造した「バベルの塔」を管理する超高性能電子頭脳です。自然言語で話し
バビル2世の良き相談相手として登場します。 &lt;a href=&quot;#fr-1-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;&#x2F;section&gt;
</content>
        <summary type="html">昨日Claudeに「Anthropic Interviewerに参加しませんか？」と見慣れぬポップアップが表示されました。回答していくと、生成AIであるClaudeに生成AIの活用方法や将来の役割をインタビューされるという奇妙な体験でした。</summary>
        </entry><entry xml:lang="en">
        <title>React Server Components RCE脆弱性（CVE-2025-55182）への対応記録</title>
        <published>2025-12-06T00:00:00+00:00</published>
        <updated>2025-12-06T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2025/12/react-nextjs-cve-2025-55182-response/" type="text/html"/>
        <id>https://codedchords.dev/blog/2025/12/react-nextjs-cve-2025-55182-response/</id>
        
            <content type="html">&lt;h2 id=&quot;脆弱性の概要&quot;&gt;脆弱性の概要&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;CVE-2025-55182とは&quot;&gt;CVE-2025-55182とは&lt;&#x2F;h3&gt;
&lt;p&gt;CVE-2025-55182は、React 19のServer Components（RSC）における「Flight」プロトコルの安全でないデシリアライゼーション（deserialize）に起因する脆弱性です。
主な特徴は次の通りです。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;CVSSスコア: 10.0（最大値）&lt;&#x2F;strong&gt;&lt;&#x2F;li&gt;
&lt;li&gt;影響範囲: React 19.0.0、19.1.0、19.1.1、19.2.0&lt;&#x2F;li&gt;
&lt;li&gt;攻撃条件: 認証不要、細工されたHTTPリクエストのみで実行可能&lt;&#x2F;li&gt;
&lt;li&gt;デフォルト設定で脆弱: &lt;code&gt;create-next-app&lt;&#x2F;code&gt;により作成した標準的なNext.jsアプリケーションが影響を受ける&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;技術的な仕組み&quot;&gt;技術的な仕組み&lt;&#x2F;h3&gt;
&lt;p&gt;この脆弱性は、RSCの内部通信プロトコルである「Flight」の処理において、攻撃者の制御可能なデータを適切な検証なしにデシリアライズしてしまうことに起因します。攻撃者からペイロードを含むHTTPリクエストが送信されると、サーバー側ではこれをFlightプロトコルのデータとして処理し、検証なしにデシリアライズします。この結果、任意のコードを実行される可能性があります。&lt;&#x2F;p&gt;
&lt;p&gt;重要なのは、この処理がアプリケーションの認証ロジックより前、つまりMiddlewareでの保護より深い層で行われるため、通常の認証機構では防げないという点です。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;CVE番号の統合経緯&quot;&gt;CVE番号の統合経緯&lt;&#x2F;h2&gt;
&lt;p&gt;2025年12月3日時点では、以下の2つのCVE番号で追跡されていました。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;CVE-2025-55182&lt;&#x2F;strong&gt;: React Server Componentsの脆弱性&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;CVE-2025-66478&lt;&#x2F;strong&gt;: Next.jsの脆弱性&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;調査の結果、Next.jsの脆弱性は実質的にReactの脆弱性に起因することが判明し、&lt;strong&gt;CVE-2025-66478は重複として却下&lt;&#x2F;strong&gt;されました。現在は&lt;strong&gt;CVE-2025-55182&lt;&#x2F;strong&gt;に統合されています。&lt;&#x2F;p&gt;
&lt;p&gt;この経緯は、脆弱性の根本原因がReactのRSC実装そのものにあり、Next.jsはその影響を受けていたに過ぎないことを示しています。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;影響を受けるバージョンと修正版&quot;&gt;影響を受けるバージョンと修正版&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;React_&#x2F;_React-dom&quot;&gt;React &#x2F; React-dom&lt;&#x2F;h3&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;影響を受けるバージョン&lt;&#x2F;th&gt;&lt;th&gt;修正済みバージョン&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;19.0.0&lt;&#x2F;td&gt;&lt;td&gt;19.0.1&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;19.1.0, 19.1.1&lt;&#x2F;td&gt;&lt;td&gt;19.1.2&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;19.2.0&lt;&#x2F;td&gt;&lt;td&gt;19.2.1&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;h3 id=&quot;Next.js&quot;&gt;Next.js&lt;&#x2F;h3&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;影響を受けるバージョン&lt;&#x2F;th&gt;&lt;th&gt;修正済みバージョン&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;15.x（全般）&lt;&#x2F;td&gt;&lt;td&gt;15.0.5, 15.1.9, 15.2.6, 15.3.6, 15.4.8, 15.5.7&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;16.x（全般）&lt;&#x2F;td&gt;&lt;td&gt;16.0.7&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;14.3.0-canary.77以降&lt;&#x2F;td&gt;&lt;td&gt;（14.x Stable版は影響なし）&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;&lt;strong&gt;注&lt;&#x2F;strong&gt;: Next.js 13.x、14.x stable版、Pages Router、Edge Runtimeは影響を受けません。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;実際の攻撃状況&quot;&gt;実際の攻撃状況&lt;&#x2F;h2&gt;
&lt;p&gt;この脆弱性は公表直後から実際に悪用されています。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;2025年12月3日: 脆弱性が公表される&lt;&#x2F;li&gt;
&lt;li&gt;同日中: 中国関連の脅威グループによる大規模な攻撃活動が観測される&lt;&#x2F;li&gt;
&lt;li&gt;2025年12月5日午前6時（UTC）以降: Wizのセンサーが複数の被害者を検知&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;この脆弱性は「React2Shell」または「React4Shell」という名称でも呼ばれ、既に実証コード（PoC）が公開されています。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;当ブログでの対応状況&quot;&gt;当ブログでの対応状況&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;対応タイムライン&quot;&gt;対応タイムライン&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;2025年12月3日&lt;&#x2F;strong&gt;: CVE-2025-55182が公表される&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;2025年12月5日&lt;&#x2F;strong&gt;: 当ブログで修正版へのアップデート実施（v1.7.1）&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;実施した対応&quot;&gt;実施した対応&lt;&#x2F;h3&gt;
&lt;p&gt;以下のパッケージを修正版にアップデートしました。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# 実施したアップデート&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;React:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 19.0.0&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; →&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 19.2.1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;React-dom:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 19.0.0&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; →&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 19.2.1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;Next.js:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 15.2.3&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; →&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 15.5.7&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;@next&#x2F;mdx:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 15.2.3&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; →&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 15.5.7&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;eslint-config-next:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 15.2.3&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; →&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 15.5.7&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;当ブログは&lt;strong&gt;CVE-2025-55182に完全対応済み&lt;&#x2F;strong&gt;であり、この脆弱性の影響を受けない安全な状態です。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;推奨される対応&quot;&gt;推奨される対応&lt;&#x2F;h2&gt;
&lt;p&gt;Next.jsやReactを使用しているプロジェクトをお持ちの方は、以下の対応を推奨します。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;1._バージョンの確認&quot;&gt;1. バージョンの確認&lt;&#x2F;h3&gt;
&lt;p&gt;まず現在のバージョンを確認します。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;npm&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; list next react react-dom&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;2._修正版へのアップデート&quot;&gt;2. 修正版へのアップデート&lt;&#x2F;h3&gt;
&lt;p&gt;該当する場合は、直ちに修正版へアップデートしてください。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# npm の場合&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;npm&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; install next@latest react@latest react-dom@latest&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# yarn の場合&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;yarn&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; add next@latest react@latest react-dom@latest&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# pnpm の場合&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;pnpm&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; add next@latest react@latest react-dom@latest&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;3._内部依存関係の確認&quot;&gt;3. 内部依存関係の確認&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;code&gt;package.json&lt;&#x2F;code&gt;だけでなく、ロックファイル（&lt;code&gt;package-lock.json&lt;&#x2F;code&gt;、&lt;code&gt;yarn.lock&lt;&#x2F;code&gt;など）も確認し、内部依存関係として古いバージョンが残っていないか確認することを強く推奨します。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# ロックファイル内のReactバージョンを確認&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;grep&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt; -A5 &amp;#39;&amp;quot;react&amp;quot;:&amp;#39; package-lock.json&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;grep&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt; -A5 &amp;#39;&amp;quot;next&amp;quot;:&amp;#39; package-lock.json&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;4._デプロイ&quot;&gt;4. デプロイ&lt;&#x2F;h3&gt;
&lt;p&gt;アップデート後は速やかにビルドとデプロイを実施してください。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;npm&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; run build&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# デプロイコマンドを実行&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;まとめ&quot;&gt;まとめ&lt;&#x2F;h2&gt;
&lt;p&gt;CVE-2025-55182は、React Server Componentsの根本的な脆弱性であり、
&lt;strong&gt;CVSS 10.0&lt;&#x2F;strong&gt;という最大の深刻度を持つ重大な問題です。デフォルト設定で脆弱であり、認証を回避して攻撃可能という特性から、速やかな対応が必要です。&lt;&#x2F;p&gt;
&lt;p&gt;当ブログでは公表から2日以内に対応を完了しましたが、既に実際の攻撃が観測されているため、まだ対応されていない方は最優先で対応することを強く推奨します。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;参考リンク&quot;&gt;参考リンク&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;react.dev&#x2F;blog&#x2F;2025&#x2F;12&#x2F;03&#x2F;critical-security-vulnerability-in-react-server-components&quot;&gt;Critical Security Vulnerability in React Server Components – React&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;nextjs.org&#x2F;blog&#x2F;CVE-2025-66478&quot;&gt;Security Advisory: CVE-2025-66478 | Next.js&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.wiz.io&#x2F;blog&#x2F;critical-vulnerability-in-react-cve-2025-55182&quot;&gt;Critical RCE Vulnerabilities Discovered in React &amp;amp; Next.js | Wiz Blog&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;unit42.paloaltonetworks.com&#x2F;cve-2025-55182-react-and-cve-2025-66478-next&#x2F;&quot;&gt;Critical Vulnerabilities in React Server Components and Next.js&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;nvd.nist.gov&#x2F;vuln&#x2F;detail&#x2F;CVE-2025-55182&quot;&gt;NVD - CVE-2025-55182&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</content>
        <summary type="html">2025年12月3日、React Server Components（RSC）とNext.jsにおいて、認証不要でリモートコード実行（RCE）が可能となる重大な脆弱性が公表されました。この記事では、この脆弱性の深刻度、CVE番号の統合経緯、そして当ブログでの対応状況について記録します。</summary>
        </entry><entry xml:lang="en">
        <title>GitHub Actionsでnpmパッケージ公開を自動化する - Trusted Publishingで実現するトークンレス運用</title>
        <published>2025-12-05T00:00:00+00:00</published>
        <updated>2025-12-05T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2025/12/automating-npm-publish-with-github-actions/" type="text/html"/>
        <id>https://codedchords.dev/blog/2025/12/automating-npm-publish-with-github-actions/</id>
        
            <content type="html">&lt;p&gt;本記事では、私が開発している&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;yostos&#x2F;jrnl-mcp&quot;&gt;jrnl-mcp&lt;&#x2F;a&gt;パッケージで実装した、
GitHubが発表した&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.blog&#x2F;changelog&#x2F;2025-09-29-strengthening-npm-security-important-changes-to-authentication-and-token-management&#x2F;&quot;&gt;npmの認証強化&lt;&#x2F;a&gt;
対応の
Trusted Publishing (OIDC) を使用したトークン管理不要の自動公開について記載しています。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;npmの認証変更の背景&quot;&gt;npmの認証変更の背景&lt;&#x2F;h2&gt;
&lt;p&gt;GitHubは2025年9月29日に、npmのセキュリティ強化として以下の変更を発表しました。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Classic Access Tokenの廃止&lt;&#x2F;li&gt;
&lt;li&gt;Trusted Publishing (OIDC) またはGranular Access Tokenへの移行推奨&lt;&#x2F;li&gt;
&lt;li&gt;より細かい権限管理の実現&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;移行先として2つの選択肢があります。&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Granular Access Token&lt;&#x2F;li&gt;
&lt;li&gt;Trusted Publishing (OIDC)&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;Granular Access Tokenは、従来のトークン方式を改良したものでパッケージごとの権限管理が可能となっていますが、定期的なトークンのローテーションが必要です。
Trusted Publishingはトークンを完全に排除した新しい認証方式で、公開を自動化しトークンを完全に排除したものです。&lt;&#x2F;p&gt;
&lt;p&gt;jrnl-mcpでは、トークン管理の手間を完全に排除できる &lt;strong&gt;Trusted Publishing&lt;&#x2F;strong&gt; を採用しました。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;自動公開の仕組み&quot;&gt;自動公開の仕組み&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;全体のフロー&quot;&gt;全体のフロー&lt;&#x2F;h3&gt;
&lt;p&gt;jrnl-mcpでは、以下のフローで自動公開を実現しています。&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;GitHubでリリースを作成&lt;&#x2F;li&gt;
&lt;li&gt;GitHub Actionsが自動起動&lt;&#x2F;li&gt;
&lt;li&gt;依存関係のインストールとテストを実行&lt;&#x2F;li&gt;
&lt;li&gt;npmへ自動公開&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;この仕組みにより、リリース作成だけでパッケージの公開が完了します。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;GitHub_Actionsの設定&quot;&gt;GitHub Actionsの設定&lt;&#x2F;h3&gt;
&lt;p&gt;実際に使用しているワークフロー設定は以下の通りです。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;yaml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;name&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; Publish to npm&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-constant z-language z-boolean&quot;&gt;on&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;  release&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;    types&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;published&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;permissions&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;  contents&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; read&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;  id-token&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; write&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;jobs&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;  publish&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;    runs-on&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; ubuntu-latest&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;    steps&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;      -&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt; name&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; Checkout code&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;        uses&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; actions&#x2F;checkout@v4&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;      -&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt; name&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; Setup Node.js&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;        uses&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; actions&#x2F;setup-node@v4&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;        with&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;          node-version&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;20&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;          registry-url&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;https:&#x2F;&#x2F;registry.npmjs.org&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;      -&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt; name&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; Install dependencies&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;        run&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; npm ci&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;      -&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt; name&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; Run tests&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;        run&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; npm run test:ci&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;      -&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt; name&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; Publish to npm&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;        run&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; npm publish --provenance --access public&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;重要なポイントは、&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;GitHubのリリース機能を使用することで、手動でのトリガーが可能になる。これにより、意図しないタイミングでの公開を防ぐ。&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;permissions&lt;&#x2F;code&gt;の設定により、GitHub Actionsはnpmに対して一時的なOIDCトークンを発行・認証する。長期的なトークンをSecretに保存する必要がない。&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;npm publish --provenance --access public&lt;&#x2F;code&gt;により自動的にprovenance（出所証明）が生成され、パッケージがどのリポジトリから公開されたか検証可能となる。&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;npm run test:ci&lt;&#x2F;code&gt;により公開前のテストを自動化する。&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;h2 id=&quot;Trusted_Publishing_の設定方法&quot;&gt;Trusted Publishing の設定方法&lt;&#x2F;h2&gt;
&lt;p&gt;Trusted Publishingを使用する場合、npm側での設定が必要です。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;1._npm_でパッケージを公開&quot;&gt;1. npm でパッケージを公開&lt;&#x2F;h3&gt;
&lt;p&gt;まず、通常の方法で初回のパッケージを公開します（トークンを使用）。npm側でパッケージが存在している必要があるためです。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;2._npm_で_Trusted_Publishing_を設定&quot;&gt;2. npm で Trusted Publishing を設定&lt;&#x2F;h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.npmjs.com&#x2F;&quot;&gt;npm のパッケージ設定&lt;&#x2F;a&gt;にアクセス&lt;&#x2F;li&gt;
&lt;li&gt;公開したパッケージの&quot;Settings&quot;タブを開く&lt;&#x2F;li&gt;
&lt;li&gt;&quot;Publishing access&quot;セクションで&quot;Add a publisher&quot;を選択&lt;&#x2F;li&gt;
&lt;li&gt;GitHub Actionsを選択し、以下を設定する
&lt;ul&gt;
&lt;li&gt;Repository: &lt;code&gt;&amp;lt;username&amp;gt;&#x2F;&amp;lt;repository-name&amp;gt;&lt;&#x2F;code&gt;（例: &lt;code&gt;yostos&#x2F;jrnl-mcp&lt;&#x2F;code&gt;）&lt;&#x2F;li&gt;
&lt;li&gt;Workflow: ワークフローファイル名（例: &lt;code&gt;publish.yml&lt;&#x2F;code&gt;）&lt;&#x2F;li&gt;
&lt;li&gt;Environment: 未指定（デフォルト）または特定の環境名&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;h3 id=&quot;3._GitHub_Actions_の設定&quot;&gt;3. GitHub Actions の設定&lt;&#x2F;h3&gt;
&lt;p&gt;前述のワークフロー設定で、&lt;code&gt;id-token: write&lt;&#x2F;code&gt; 権限を付与するだけで完了です。トークンをSecretに保存する必要はありません。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;トークンベースとの比較&quot;&gt;トークンベースとの比較&lt;&#x2F;h3&gt;
&lt;p&gt;Trusted Publishingを使用することで、以下の作業が不要になります。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;npmトークンの作成と保存&lt;&#x2F;li&gt;
&lt;li&gt;GitHub Secretsへのトークン登録&lt;&#x2F;li&gt;
&lt;li&gt;トークンの定期的なローテーション（Granular Access Tokenの場合、最大90日ごと）&lt;&#x2F;li&gt;
&lt;li&gt;トークン漏洩のリスク管理&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;まとめ&quot;&gt;まとめ&lt;&#x2F;h2&gt;
&lt;p&gt;Trusted Publishing (OIDC) とGitHub Actionsを使用したnpmパッケージの自動公開により、以下のメリットが得られました。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;公開作業の効率化&lt;&#x2F;li&gt;
&lt;li&gt;トークン管理の完全な排除&lt;&#x2F;li&gt;
&lt;li&gt;セキュリティの向上&lt;&#x2F;li&gt;
&lt;li&gt;品質の担保&lt;&#x2F;li&gt;
&lt;li&gt;透明性の確保（自動provenance生成）&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;特に、Trusted Publishingの導入により、トークンの定期的なローテーションや漏洩リスクの心配が不要になり、セキュリティと運用性が大幅に向上しました。npmパッケージを公開している方は、ぜひTrusted Publishingへの移行とGitHub Actionsによる自動化を検討してみてください。&lt;&#x2F;p&gt;
&lt;p&gt;Granular Access Tokenでもセキュリティは向上しますが、定期的なローテーション（最大90日ごと）が必要なため、可能であればTrusted Publishingの使用を推奨します。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;参考リンク&quot;&gt;参考リンク&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.blog&#x2F;changelog&#x2F;2025-09-29-strengthening-npm-security-important-changes-to-authentication-and-token-management&#x2F;&quot;&gt;Strengthening npm security: Important changes to authentication and token management&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;yostos&#x2F;jrnl-mcp&quot;&gt;jrnl-mcp GitHub Repository&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;docs.npmjs.com&#x2F;about-access-tokens&quot;&gt;npm Documentation: About access tokens&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</content>
        <summary type="html">npm パッケージの公開を手動で行っていると、毎回トークンの管理やビルド、テストの実行など煩雑な作業が発生します。また、2025 年 9 月 29 日に GitHub が発表したnpmの認証強化により、Classic Token の廃止と、Trusted Publishing または Granular Access Token への移行が必要になりました。Trusted Publishing (OIDC) を使ってトークン管理不要のセキュアな公開フローを構築した手順を解説します。</summary>
        </entry><entry xml:lang="en">
        <title>技術無知が経営リスクになった理由</title>
        <published>2025-11-08T00:00:00+00:00</published>
        <updated>2025-11-08T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2025/11/tech-ignorance-is-business-liability-ja/" type="text/html"/>
        <id>https://codedchords.dev/blog/2025/11/tech-ignorance-is-business-liability-ja/</id>
        
            <content type="html">&lt;!-- textlint-disable --&gt;
&lt;img
  src=&quot;https:&amp;#x2F;&amp;#x2F;codedchords.dev&amp;#x2F;blog&amp;#x2F;2025&amp;#x2F;11&amp;#x2F;tech-ignorance-is-business-liability-ja&amp;#x2F;noitdept.webp?h=074677f7f792dfd9f5b2&quot;
  alt=&quot;No IT dept&quot; width=&quot;1456&quot; height=&quot;816&quot; loading=&quot;lazy&quot;
&#x2F;&gt;&lt;!-- textlint-enable --&gt;
&lt;details&gt;
&lt;summary&gt;Table of Contents&lt;&#x2F;summary&gt;
  &lt;!-- toc --&gt;
&lt;&#x2F;details&gt;
&lt;h2 id=&quot;業務システム台帳とは何か&quot;&gt;業務システム台帳とは何か&lt;&#x2F;h2&gt;
&lt;p&gt;「業務システム台帳」とは、組織が所有する業務システムを記録し、一覧化する台帳です。重要なのは、各システムの内部構造や技術的な詳細を管理するものではないということです。&lt;&#x2F;p&gt;
&lt;p&gt;具体的には、台帳にはシステムの以下のような基本的な属性を記録します。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;システム名。組織内で一意に識別できる名称(例。財務システム、販売管理システム、人事管理システム)&lt;&#x2F;li&gt;
&lt;li&gt;業務プロセス。システムがサポートする業務プロセスの名称。これにより、システムが組織にどのような価値を提供しているかが可視化される。前提として、組織が業務プロセスの台帳も整備していることが望ましい&lt;&#x2F;li&gt;
&lt;li&gt;業務プロセスオーナー。これも重要な属性である。システムの責任者が誰で、予算を管理しているかが明確になる。これがないと、システムに関する意思決定やライフサイクル管理が曖昧になる&lt;&#x2F;li&gt;
&lt;li&gt;重要度。システムが事業継続計画(BCP)の対象となる重要システムなのか、停止しても業務への影響が限定的なシステムなのかを分類する。リスク管理や投資の優先順位を決定するために不可欠な情報である&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;業務システム台帳は、ITガバナンスの最も基本的な構成要素です。組織が自分の所有物を理解していなければ、適切な投資判断、リスク管理、コスト最適化は始まりません。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;業務システム台帳の重要性&quot;&gt;業務システム台帳の重要性&lt;&#x2F;h2&gt;
&lt;p&gt;近年、ランサムウェアに攻撃される企業が増えています。ランサムウェアはシステムとデータを暗号化し、業務を数ヶ月にわたって停止させます。このような危機的状況において、業務システム台帳が存在しなかったらどうなるでしょうか。&lt;&#x2F;p&gt;
&lt;p&gt;何が破壊され、何を復旧すべきかを誰も把握できません。どのシステムが業務にとって最も重要でしょうか。各システムのデータバックアップはどこにあるのでしょうか。そもそも組織全体でいくつのシステムが稼働していたのでしょうか。この基本的な情報がなければ、復旧作業は極めて混乱し、事業再開は大幅に遅れることになります。業務システム台帳は危機管理のための最も基本的なインフラです。&lt;&#x2F;p&gt;
&lt;p&gt;もう1つの重要な側面は、会計要件に起因します。請負契約で開発されたシステムは無形固定資産として減価償却する必要があり、運用段階での機能強化も資産計上の対象となります。しかし、会計資産台帳だけでは、どの機能強化が資産計上に値するかといった業務システム固有の判断は難しいです。会計資産台帳と整合性のとれた業務システム台帳が必要です。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;なぜ組織は業務システム台帳を維持できないのか&quot;&gt;なぜ組織は業務システム台帳を維持できないのか&lt;&#x2F;h2&gt;
&lt;p&gt;多くの組織は他社の災害を目撃し、危機感に駆られて台帳の整備を始めます。しかし、ほとんどの場合、台帳は作成された瞬間から忘れ去られ、やがて古くなり、闇に葬られます。&lt;&#x2F;p&gt;
&lt;p&gt;例えば、ある部門が独自にシステムを調達したが、台帳には登録されません。別のシステムは対応する業務プロセスを拡大するために大規模な機能強化を行ったが、台帳には反映されません。このようにして、台帳は徐々に現実と乖離し、役に立たなくなり、最終的には廃棄されます。&lt;&#x2F;p&gt;
&lt;p&gt;なぜこのようなことが起こるのでしょうか。マーフィーの法則は「うまくいかなくなる可能性のあることは、うまくいかなくなる」と述べています。しかも、我々はITガバナンスの確立に失敗した機能不全の組織について語っているのです。そのような組織において、人々の善意と勤勉さに頼る運用は、いずれ必ず失敗します。&lt;&#x2F;p&gt;
&lt;p&gt;では、どうすれば台帳を維持できるのでしょうか。鍵は金の流れです。部門のシステム調達も、大規模なシステム強化も、必ず金銭取引を伴います。この金の流れを捕捉できれば、台帳の変更を見逃さないトリガーとして利用できます。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;業務システム台帳を維持する仕組み&quot;&gt;業務システム台帳を維持する仕組み&lt;&#x2F;h2&gt;
&lt;p&gt;前節で述べたように、鍵は金の流れを捕捉することです。業務システムに関連する財務プロセスは、予算編成、支出(調達)、固定資産会計の3つです。これらのプロセスに台帳の更新を組み込むことで、台帳を自動的に維持する仕組みを確立できます。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;予算編成&quot;&gt;予算編成&lt;&#x2F;h3&gt;
&lt;p&gt;業務システムを運用または変更するには予算編成が必要です。一般的に、予算は予算コード(勘定科目コード)と予算額で管理されます。したがって、予算編成プロセスでは以下の2つが必要です。&lt;&#x2F;p&gt;
&lt;p&gt;予算が業務システムに関連する場合、業務システム台帳のレコードとリンクさせなければなりません。この段階で業務システムが業務システム台帳に登録されていない場合は、新しいシステムとみなし、台帳に追加しなければなりません。このようにして、台帳にないシステムへの予算編成を防ぐことができます。&lt;&#x2F;p&gt;
&lt;p&gt;次に、予算編成プロセスの完了時に、運用中または運用予定のすべての業務システムに予算が配分されているかを確認します。予算が割り当てられていないにもかかわらず稼働している運用業務システムのオーナーには、予算配分を義務付けます。&lt;&#x2F;p&gt;
&lt;p&gt;重要なのは、台帳を維持するために台帳の更新を要求するのではなく、台帳と整合性がとれていなければ予算処理を完了できない仕組みを組み込むことです。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;支出(調達)&quot;&gt;支出(調達)&lt;&#x2F;h3&gt;
&lt;p&gt;業務システムの導入、変更、保守には必ず支出が発生します。IT部門が確立されていない組織では、これらの支出は通常、調達部門または経理部門を通じて処理されます。この調達プロセス自体が、台帳を維持するための最も信頼できるトリガーとなります。&lt;&#x2F;p&gt;
&lt;p&gt;業務システムに関連する発注や契約は、どの予算に紐づいているかで識別できるはずです。業務システムに関連すると識別された調達については、発注時と納品時の両方で業務システム台帳とのリンクと整合性を確保することを義務付けるべきです。これにより、「部門が独自にシステムを調達したが、台帳には追加されなかった」といった失敗パターンを防ぐことができます。&lt;&#x2F;p&gt;
&lt;p&gt;調達プロセスに台帳の整合性チェックを組み込むことで、多くの企業はこのチェックを迂回した調達を逸脱、つまり「BYPASS」として扱い、要求部門にペナルティを課します。将来的には、これらのチェックは組織のITガバナンスフレームワークの一部としても機能し、導入されるシステムが組織の意図するアーキテクチャに合致しているかを確認するレビューポイントとしても機能します。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;固定資産会計&quot;&gt;固定資産会計&lt;&#x2F;h3&gt;
&lt;p&gt;請負契約で開発された業務システムは、組織の無形固定資産として記録され、減価償却の対象となります。SaaSなどのサービスベースの契約は資産として計上されませんが、発注・納品されるシステムは会計上も適切に管理しなければなりません。&lt;&#x2F;p&gt;
&lt;p&gt;IT部門がない組織では「引き渡し」を捕捉するプロセスがないため、納品時に無形固定資産台帳の更新と業務システム台帳の更新をリンクさせる仕組みが不可欠です。システムオーナーは、機能強化が資産計上に値するかを判断し、経理部門に台帳の更新を依頼しなければなりません。この整合性チェックが完了するまで検収を完了できないようなプロセスを設計することで、両方の台帳が確実に更新されます。&lt;&#x2F;p&gt;
&lt;p&gt;この仕組みには2つの効果があります。組織の会計実務が正確であれば、無形固定資産台帳には資産計上が必要なすべてのシステムが正しく記録されているはずです。この台帳との整合性を維持することで、業務システム台帳の信頼性が高まります。逆に、会計実務が不正確な場合、業務システム台帳との整合性を確保する仕組みを確立することで、不適切な会計処理を防ぐことができます。&lt;&#x2F;p&gt;
&lt;p&gt;重要なのは、この整合性チェックを検収プロセスに組み込むことで、人間の善意に依存することなく、両方の台帳が確実に維持されることです。この検証なしには検収を完了できないようにすれば、更新は標準的なワークフローの一部として自動的に行われます。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;結論&quot;&gt;結論&lt;&#x2F;h2&gt;
&lt;p&gt;業務システム台帳すら整備していない組織は、たとえ危機感に駆られて作成したとしても、それを維持できません。作成した瞬間から劣化し始めることは明らかです。&lt;&#x2F;p&gt;
&lt;p&gt;重要なのは、それを維持する仕組みです。金の流れに伴う避けられないプロセス、すなわち予算、調達、会計に、台帳を更新・維持する仕組みを組み込むことが重要です。&lt;&#x2F;p&gt;
&lt;p&gt;逆に言えば、この仕組みを確立するだけで、ITガバナンスへの第一歩を踏み出すことができます。難しいことではありません。システムに関連する金の流れを捕捉すればよいだけです。それすらできないのであれば、あなたの組織はITガバナンス以前にコーポレートガバナンスの基本すら備わっていません。まあ、そうなのでしょうけれど。&lt;&#x2F;p&gt;
</content>
        <summary type="html">この記事はIT部門を持たず、非技術部門だけでベンダーに作らせた業務システムを所有し運用している組織について想定しています。きっとランサムウェアで危機に見舞われているアサヒビールやアスクルを見て震え上がって、何をすればいいか焦っている組織も多いと思います。そんな組織が行なうべき第一歩として業務システム台帳の整備について解説しています。</summary>
        </entry><entry xml:lang="en">
        <title>Because Your Tech Ignorance Is Now a Business Liability</title>
        <published>2025-11-08T00:00:00+00:00</published>
        <updated>2025-11-08T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2025/11/tech-ignorance-is-business-liability/" type="text/html"/>
        <id>https://codedchords.dev/blog/2025/11/tech-ignorance-is-business-liability/</id>
        
            <content type="html">&lt;!-- textlint-disable --&gt;
&lt;img
  src=&quot;https:&amp;#x2F;&amp;#x2F;codedchords.dev&amp;#x2F;blog&amp;#x2F;2025&amp;#x2F;11&amp;#x2F;tech-ignorance-is-business-liability&amp;#x2F;noitdept.webp?h=074677f7f792dfd9f5b2&quot;
  alt=&quot;No IT dept&quot; width=&quot;1456&quot; height=&quot;816&quot; loading=&quot;lazy&quot;
&#x2F;&gt;&lt;!-- textlint-enable --&gt;
&lt;details&gt;
&lt;summary&gt;Table of Contents&lt;&#x2F;summary&gt;
  &lt;!-- toc --&gt;
&lt;&#x2F;details&gt;
&lt;h2 id=&quot;What_is_Application_System_Inventory?&quot;&gt;What is Application System Inventory?&lt;&#x2F;h2&gt;
&lt;p&gt;&quot;Application System Inventory&quot; is an inventory that records and keeps a list of application systems the organization owns. The important point is that it does not manage the internal structure of each system or technical details.&lt;&#x2F;p&gt;
&lt;p&gt;More specifically, the inventory stores the following basic attributes of systems.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;System Name: A name that can be uniquely identified within the organization (e.g. Finance System, Sales Management System, Human Resource Management System).&lt;&#x2F;li&gt;
&lt;li&gt;Business Process: A name of the business process that the system supports. This makes visible what kind of value the system provides to the organization. As a prerequisite, it is desirable that the organization also maintains an inventory of its business processes.&lt;&#x2F;li&gt;
&lt;li&gt;Business Process Owner: This is also an important attribute. This clarifies who is responsible for the system and manages the budget for it. Without this, decision-making and life-cycle management for the system become ambiguous.&lt;&#x2F;li&gt;
&lt;li&gt;Importance: This classifies whether the system is a critical system that is subject to Business Continuity Planning(BCP), or a system whose impact on business operations is limited even if it stops. This is essential information for risk management and determining investment priorities.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Application System Inventory is the most fundamental component of IT governance. If the organization doesn&#x27;t understand what it owns, appropriate investment decisions, risk management, and cost optimization cannot begin.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;Why_Application_System_Inventory_Is_Important&quot;&gt;Why Application System Inventory Is Important&lt;&#x2F;h2&gt;
&lt;p&gt;In recent months, an increasing number of enterprises have been attacked by ransomware. The ransomware encrypts their systems and data, disrupting business operations for several months. In such critical situations, what happens if Application System Inventory does not exist?&lt;&#x2F;p&gt;
&lt;p&gt;No one would be able to understand what has been destroyed and what should be restored. Which systems are most critical for business operations? Where are the data backups for each system located? How many systems were operating across the organization in the first place? Without this basic information, recovery efforts would become extremely chaotic, and business resumption would be significantly delayed. Application System Inventory is the most fundamental infrastructure for crisis management.&lt;&#x2F;p&gt;
&lt;p&gt;Another important aspect is driven by accounting requirements.
Systems developed under a work contract (&quot;Ukeoi&quot; contract)
need to be depreciated as intangible fixed assets.
Functional enhancements during the operational phase are also
subject to capitalization. However, with only the accounting
asset ledger, it is difficult to make judgments specific to
Application Systems, such as which functional enhancements
warrant capitalization. An Application System Inventory that
is aligned with the accounting asset ledger is necessary.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;Why_Organizations_Cannot_Maintain_Application_System_Inventory&quot;&gt;Why Organizations Cannot Maintain Application System Inventory&lt;&#x2F;h2&gt;
&lt;p&gt;Many organizations witness other companies&#x27; disasters and begin to establish their Inventory, driven by a sense of crisis. However, in most cases, the inventory is forgotten from the moment it is created and eventually becomes outdated and buried in the darkness.&lt;&#x2F;p&gt;
&lt;p&gt;For example, a department procures a system independently, but it is not registered in the inventory. Another system undergoes major enhancements to expand the business processes it supports, but this is not reflected in the inventory. In this way, the inventory gradually diverges from reality, becomes useless, and is eventually discarded.&lt;&#x2F;p&gt;
&lt;p&gt;Why does this happen? Murphy&#x27;s Law states, &quot;Anything that can go wrong will go wrong.&quot; Moreover, we are talking about dysfunctional organizations that have failed to establish IT Governance. Operations that rely on the goodwill and diligence of people in such organizations are bound to fail at some point.&lt;&#x2F;p&gt;
&lt;p&gt;So how can we maintain the Inventory? The key is the flow of money. Both departmental system procurement and major system enhancements are always accompanied by financial transactions. If you can capture this flow of money, you can use it as a trigger that won&#x27;t miss changes to the Inventory.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;The_Mechanism_to_Maintain_Application_System_Inventory&quot;&gt;The Mechanism to Maintain Application System Inventory&lt;&#x2F;h2&gt;
&lt;p&gt;As described in the previous section, the key is to capture the flow of money. There are three financial processes related to Application System: budgeting, expenditure(procurement), and fixed asset accounting. By incorporating Inventory updates into these processes, you can establish a mechanism to maintain the Inventory automatically.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;Budgeting&quot;&gt;Budgeting&lt;&#x2F;h3&gt;
&lt;p&gt;Budgeting must be done for operating or modifying an Application System. Generally, budgets are managed using budget codes or account codes, along with budget amounts. Therefore, the following two things are required during the budgeting process:&lt;&#x2F;p&gt;
&lt;p&gt;If the budget is related to Application System, it must be linked to a record in the Application System Inventory. If, at this stage, the Application System isn&#x27;t registered in the Application System Inventory, it must be considered a new system and should be added to the inventory as such. In this way, you can prevent budgeting for systems that are not in the Inventory.&lt;&#x2F;p&gt;
&lt;p&gt;Next, at the completion of the budgeting process, you verify whether some budget has been allocated to all Application Systems that are either operational or planned to be operational. You mandate budget allocation for the owners of operational application systems that are running despite not having an assigned budget.&lt;&#x2F;p&gt;
&lt;p&gt;The important point is not to require Inventory updates to maintain it, but to incorporate a mechanism in which budget processing cannot be completed without being consistent with the Inventory.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;Expenditure(Procurement)&quot;&gt;Expenditure(Procurement)&lt;&#x2F;h3&gt;
&lt;p&gt;The introduction, modification, and maintenance of Application Systems always incur expenditures. In organizations without an established IT department, these expenditures are typically processed through the procurement or accounting departments. This procurement process itself becomes the most reliable trigger for maintaining the Inventory.&lt;&#x2F;p&gt;
&lt;p&gt;Orders and contracts related to Application Systems should be
identifiable based on which budget they are tied to.&lt;&#x2F;p&gt;
&lt;p&gt;For procurements related to Application Systems,
it should be mandatory to ensure linkage and consistency
with the Application System Inventory.
This applies both at the time of ordering and at delivery.
This prevents failure patterns such as
&quot;a department independently procured a system, but it was
never added to the Inventory.&quot;&lt;&#x2F;p&gt;
&lt;p&gt;By embedding an Inventory consistency check within the
procurement process, many companies treat any procurement
that bypasses this check as a deviation—a &quot;BYPASS&quot;.
They impose penalties on the requesting department.&lt;&#x2F;p&gt;
&lt;p&gt;In the future, these checks will also function as part of
the organization&#x27;s IT Governance framework. They serve as a
review point to verify whether systems being introduced
align with the organization&#x27;s intended architecture.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;Fixed_Asset_Accounting&quot;&gt;Fixed Asset Accounting&lt;&#x2F;h3&gt;
&lt;p&gt;Application Systems developed under contract should be recorded as intangible fixed assets of the organization and are subject to depreciation. Service-based agreements such as SaaS are not capitalized as assets, but systems that are ordered and delivered must still be properly managed from an accounting perspective.&lt;&#x2F;p&gt;
&lt;p&gt;In organizations without an IT department, there is no
&quot;handover&quot; capture process. Therefore, a mechanism that links
the update of the intangible fixed asset ledger with the
Application System Inventory upon delivery is essential.
The system owner must determine whether a functional
enhancement qualifies for capitalization and request the
accounting department to update the ledger. By designing
a process that prevents acceptance until this consistency
check is completed, both ledgers are reliably updated.&lt;&#x2F;p&gt;
&lt;p&gt;This mechanism has two effects. If the organization&#x27;s accounting practices are accurate, the intangible fixed asset ledger should correctly record all systems that need to be capitalized. Maintaining consistency with this ledger enhances the reliability of the Application System Inventory. Conversely, if accounting practices are inaccurate, establishing a mechanism to ensure consistency with the Application System Inventory helps prevent improper accounting treatments.&lt;&#x2F;p&gt;
&lt;p&gt;Crucially, embedding this consistency check into the acceptance process ensures that both ledgers are maintained reliably without depending on human goodwill. When acceptance cannot be completed without this verification, the updates happen automatically as part of the standard workflow.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;Conclusion&quot;&gt;Conclusion&lt;&#x2F;h2&gt;
&lt;p&gt;Organizations that have not even established an Application System Inventory, even if driven by a sense of crisis to create one, will not be able to maintain it. It is clear that it will start to decay from the moment it is created.&lt;&#x2F;p&gt;
&lt;p&gt;What matters is the mechanism to maintain it. It is important to embed the mechanism for updating and maintaining the Inventory into the unavoidable processes that accompany the flow of money: budget, procurement, and accounting.&lt;&#x2F;p&gt;
&lt;p&gt;Conversely, if you simply establish this mechanism, you can take the first step toward IT governance. It is not difficult. You just need to capture the flow of money related to systems. If you cannot even do that, your organization does not have the fundamentals of corporate governance in place even before considering IT governance—though that is likely the case.&lt;&#x2F;p&gt;
</content>
        <summary type="html">この記事はIT部門を持たず、非技術部門だけでベンダーに作らせた業務システムを所有し運用している組織について想定しています。きっとランサムウェアで危機に見舞われているアサヒビールやアスクルを見て震え上がって、何をすればいいか焦っている組織も多いと思います。そんな組織が行なうべき第一歩として業務システム台帳の整備について解説しています。</summary>
        </entry><entry xml:lang="en">
        <title>OpenAI Chairman Says a Dot-Com-Like Bust Wouldn’t Be All Bad</title>
        <published>2025-10-31T00:00:00+00:00</published>
        <updated>2025-10-31T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2025/10/dot-com-like-bust/" type="text/html"/>
        <id>https://codedchords.dev/blog/2025/10/dot-com-like-bust/</id>
        
            <content type="html">&lt;p&gt;「&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;news.bloomberglaw.com&#x2F;artificial-intelligence&#x2F;openai-chairman-says-a-dot-com-like-bust-wouldnt-be-all-bad&quot;&gt;OpenAI Chairman Says a Dot-Com-Like Bust Wouldn’t Be All Bad&lt;&#x2F;a&gt;」&lt;&#x2F;p&gt;
&lt;p&gt;Bloombergに掲載されたOpenAI会長Bret Taylorのインタビュー記事です。&lt;&#x2F;p&gt;
&lt;p&gt;今の生成AIブームを2000年代のドットコム・バブルと重ねて、
バブルが崩壊したとしてもそこからGoogleやAmazonのような企業が
生まれ生き残り次の世代の主役になったことを考えると、健全だと語っています。&lt;&#x2F;p&gt;
&lt;p&gt;確かに今年のノーベル経済学賞を受賞した「アギヨン・ホーウィット理論」
でも「創造的破壊」が経済発展を齎すことを数学モデルで証明しています。
この理論からも、バブル崩壊が必ずしも悪いことではないと言えるでしょう。&lt;&#x2F;p&gt;
&lt;p&gt;翻って日本の現状を見ると、国や自治体が補助金や支援策で会社を潰さないよう延命させる政策が当然のように行われています。
しかし、この理論に従うと、これは「創造的破壊」を阻害し、経済の新陳代謝を妨げる決定的に間違った政策です。
非効率な企業を温存することで、本来そこに投入されるべきリソース（人材、資金、土地）が、
より生産性の高い新興企業や成長分野に回らない。この硬直化が日本経済の停滞の一因となっています。&lt;&#x2F;p&gt;
&lt;p&gt;また、Taylor氏が指摘する&lt;strong&gt;上司や取締役を喜ばせるための見かけ倒しの AI プロジェクトはやめるべきだ&lt;&#x2F;strong&gt;という警鐘も重要です。
先日、方針やビジョンを出さないにも関わらず、「課員に向けた生成AI研修をやってくれ」という
厚顔無恥さを発揮した理事長を目にしました。
これこそ、実質的な価値を生まない「見かけ倒しのAIプロジェクト」の典型例でしょう。&lt;&#x2F;p&gt;
</content>
        <summary type="html">OpenAI会長のインタビューから、生成AIブームとドットコム・バブルの比較、創造的破壊の重要性を考察。日本の補助金政策が経済の新陳代謝を妨げている問題と、実質的な価値を生まない見かけ倒しのAIプロジェクトへの警鐘について論じる。</summary>
        </entry><entry xml:lang="en">
        <title>Claude Sonnet 4.5リリース</title>
        <published>2025-10-03T00:00:00+00:00</published>
        <updated>2025-10-03T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2025/10/claude-4-5/" type="text/html"/>
        <id>https://codedchords.dev/blog/2025/10/claude-4-5/</id>
        
            <content type="html">&lt;details&gt;
&lt;summary&gt;Table of Contents&lt;&#x2F;summary&gt;
  &lt;!-- toc --&gt;
&lt;&#x2F;details&gt;
&lt;h2 id=&quot;tl;dr&quot;&gt;tl;dr&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;strong&gt;Claude Sonnet 4.5&lt;&#x2F;strong&gt; の詳細は
&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.anthropic.com&#x2F;news&#x2F;claude-sonnet-4-5&quot;&gt;Anthropic のアナウンス&lt;&#x2F;a&gt; を読んでもらうとして、
まとめると次のような点が変更となっています。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;コーディング、ソフトウェアエンジニアリング性能がどえらい高い。Opus 4.1と比較しても負けない&lt;&#x2F;li&gt;
&lt;li&gt;人間の感覚に近づいた(ミスアラインメント軽減)&lt;&#x2F;li&gt;
&lt;li&gt;Claude Codeがv 2.0.0にアプデされ、チェックポイント機能が付いた&lt;&#x2F;li&gt;
&lt;li&gt;Claude Code SDKがClaude Agent SDKに&lt;&#x2F;li&gt;
&lt;li&gt;Claude for ChromeがMaxユーザー（ウェイトリスト登録者）に提供開始&lt;&#x2F;li&gt;
&lt;li&gt;Claude APIのコンテキスト管理に機能追加&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;Claude_Code_v_2&quot;&gt;Claude Code v 2&lt;&#x2F;h2&gt;
&lt;p&gt;Claude CodeがV 2となりました。&lt;&#x2F;p&gt;
&lt;p&gt;インストールは以下のコマンドで行ないます。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;npm&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; install -g @anthropic-ai&#x2F;claude-code&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;主な変更点は次の通りです。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;チェックポイント機能が追加された。変更前のタイミングでコードを自動保存し、&lt;code&gt;&#x2F;rewind&lt;&#x2F;code&gt; コマンド(ESCキーを2回押下でも可)で
前のバージョン戻すことが可能となった。復元は、コード、会話、またはその両方を選ぶことができる。&lt;&#x2F;li&gt;
&lt;li&gt;思考モードをタブキーで切り替えることが出来るようになった。&lt;&#x2F;li&gt;
&lt;li&gt;Ctrl-Rキーで履歴の検索が可能となった。&lt;&#x2F;li&gt;
&lt;li&gt;利用状況を確認する &lt;code&gt;&#x2F;usage&lt;&#x2F;code&gt;コマンドが追加となった。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;Claude_API_のコンテキスト管理機能&quot;&gt;Claude API のコンテキスト管理機能&lt;&#x2F;h2&gt;
&lt;p&gt;Claude Developer Platformに、より長く複雑なエージェントタスクを実行するための新機能が追加されました。&lt;&#x2F;p&gt;
&lt;p&gt;主な機能は次の通りです。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;コンテキスト編集機能&lt;&#x2F;strong&gt;: トークン制限に近づいた際、古いツール呼び出しと結果をコンテキストウィンドウから自動的にクリアする。&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;メモリツール&lt;&#x2F;strong&gt;: ファイルベースのシステムを通じて、コンテキストウィンドウの外に情報を保存し参照できる。専用のメモリディレクトリでファイルの作成、読み取り、更新、削除が可能である。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;これらの機能により、以下のようなことが実現できるようになります。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;長期的なコーディングプロジェクトで、デバッグ中に発見した洞察を保存し、翌日のセッションでも活用できる&lt;&#x2F;li&gt;
&lt;li&gt;調査・研究タスクで、複数のドキュメントから重要な情報を蓄積し、ナレッジベースを構築できる&lt;&#x2F;li&gt;
&lt;li&gt;大規模なデータ処理ワークフローで、コンテキストが満杯になっても処理を継続できる&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;これらの機能を組み合わせることで、ベースラインと比較して39%のパフォーマンス向上が確認されています。&lt;&#x2F;p&gt;
&lt;p&gt;なお、これらはAPIを利用してエージェントやアプリケーションを構築する開発者向けの機能です。Amazon BedrockおよびGoogle CloudのVertex AIでも利用可能です。&lt;&#x2F;p&gt;
</content>
        <summary type="html">9月30日にClaude Sonnet 4.5がリリースされました。</summary>
        </entry><entry xml:lang="en">
        <title>フォント編集ソフト OTEdit問題</title>
        <published>2025-09-20T00:00:00+00:00</published>
        <updated>2025-09-20T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2025/09/otedit-problem/" type="text/html"/>
        <id>https://codedchords.dev/blog/2025/09/otedit-problem/</id>
        
            <content type="html">&lt;details&gt;
&lt;summary&gt;Table of Contents&lt;&#x2F;summary&gt;
  &lt;!-- toc --&gt;
&lt;&#x2F;details&gt;
&lt;p&gt;フォント編集ソフト「OTEdit」で作成されたフォントの空グリフ問題について解説。Adobe-Japan1文字集合選択時に発生する空グリフによりフォールバック機能が正常に動作しない問題と、Pythonスクリプトを使った修正方法を紹介。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;OTEditとは&quot;&gt;OTEditとは&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;strong&gt;OTEdit&lt;&#x2F;strong&gt;とは、&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;opentype.jp&#x2F;&quot;&gt;武蔵システム&lt;&#x2F;a&gt;が販売する
OpenTypeフォントを作成・編集を行なうアプリケーションです。
Windows版とMac版が販売されています。&lt;&#x2F;p&gt;
&lt;p&gt;この手のアプリケーションとしては比較的安価で、使用しているフォント作家の方も多いようです。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;OTEditの問題&quot;&gt;OTEditの問題&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;em&gt;(以下の考察は、OTEditの試用版による短時間の検証に基づいています。全ての機能を検証できている訳ではないので誤りを含む可能性があります。)&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;OTEditではAdobe-Japan1-3、Adobe-Japan1-4、 Adobe-Japan1-7の3種の文字集合のフォントを作成できます。
新規作成時に選択した文字集合について全てのグリフを設定することを前提としているようです。
OTEditではフォントの新規作成時に選択した文字集合から文字の削除ができず、グリフが作成されなくとも「空グリフ」と
各文字コードとグリフのcmapを作成してしまいます。&lt;&#x2F;p&gt;
&lt;p&gt;すべてのフォントがAdobe社の策定した日本語文字集合規格で作成されればよいのですが、
実際にはいずれかの文字集合を選択してもすべてのグリフをサポートしないフォントも多いようです。
例えば、IPAが配布するIPAフォントです。このフォントがどんなツールを使用して作成されたか不明ですが、
JIS X 0213:2012の文字集合をサポートしておりAdobe社の文字集合規格には従っていません。
Adobeの規格と並べると下表のような食い違いがあります。&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;文字セット&lt;&#x2F;th&gt;&lt;th&gt;総文字数&lt;&#x2F;th&gt;&lt;th&gt;JIS第1～2水準（6,355字）&lt;&#x2F;th&gt;&lt;th&gt;JIS第3～4水準（3,695字）&lt;&#x2F;th&gt;&lt;th&gt;JIS規格外文字（異体字・独自文字）&lt;&#x2F;th&gt;&lt;th&gt;主な特徴&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;JIS X 0213:2012&lt;&#x2F;td&gt;&lt;td&gt;11,233文字&lt;&#x2F;td&gt;&lt;td&gt;完全対応&lt;&#x2F;td&gt;&lt;td&gt;完全対応&lt;&#x2F;td&gt;&lt;td&gt;含まない&lt;&#x2F;td&gt;&lt;td&gt;公的規格・政府標準&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Adobe-Japan1-3&lt;&#x2F;td&gt;&lt;td&gt;9,354文字&lt;&#x2F;td&gt;&lt;td&gt;完全対応&lt;&#x2F;td&gt;&lt;td&gt;非対応&lt;&#x2F;td&gt;&lt;td&gt;機種依存文字等含む&lt;&#x2F;td&gt;&lt;td&gt;一般用途標準&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Adobe-Japan1-4&lt;&#x2F;td&gt;&lt;td&gt;15,444文字&lt;&#x2F;td&gt;&lt;td&gt;完全対応&lt;&#x2F;td&gt;&lt;td&gt;一部対応&lt;&#x2F;td&gt;&lt;td&gt;多数の独自文字・異体字含む&lt;&#x2F;td&gt;&lt;td&gt;商業印刷用&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Adobe-Japan1-7&lt;&#x2F;td&gt;&lt;td&gt;23,060文字&lt;&#x2F;td&gt;&lt;td&gt;完全対応&lt;&#x2F;td&gt;&lt;td&gt;完全対応&lt;&#x2F;td&gt;&lt;td&gt;大量の独自文字・異体字含む&lt;&#x2F;td&gt;&lt;td&gt;最上位規格&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;このようなケースでは、OTEditがcmapを生成しますが作者がグリフを用意していない文字には「空グリフ」をマッピングしてしまいます。&lt;&#x2F;p&gt;
&lt;p&gt;通常の使用ではあまり問題にならないかもしれませんが、フォント表示の際にフォールバックを前提にしている
ターミナルやブラウザなどで使用するとマズいことになります。
本来であれば指定したフォントがグリフを持たない場合は、別のフォントのグリフが表示されます。
しかしOTEditで作成したフォントでは、「空グリフ」が設定されている可能性が高いので「空白」が表示されてしまいます。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;フォントの修正&quot;&gt;フォントの修正&lt;&#x2F;h2&gt;
&lt;p&gt;最近購入した中村書体室の「カドマ-R」でこの不具合の遭遇したので、
作者の方に相談させていただき手元のフォントに修正を掛けました。&lt;&#x2F;p&gt;
&lt;p&gt;対応は、空グリフと思われる文字を調査し該当文字についてcmapからエントリーを削除するという乱暴なものです。
以下がそのスクリプトです。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;分析スクリプト&quot;&gt;分析スクリプト&lt;&#x2F;h3&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;python&quot; data-name=&quot;font_analyze.py&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;#!&#x2F;usr&#x2F;bin&#x2F;env python3&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# -*- coding: utf-8 -*-&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# HomebrewのPython環境でFontToolsを使用&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;sys&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;path&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;insert&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;0&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;#39;&#x2F;opt&#x2F;homebrew&#x2F;Cellar&#x2F;fonttools&#x2F;4.59.2&#x2F;libexec&#x2F;lib&#x2F;python3.13&#x2F;site-packages&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-control z-flow z-python&quot;&gt;try&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;    from&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; fontTools&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;ttLib&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; import&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; TTFont&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;    from&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; fontTools&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;pens&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;recordingPen&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; import&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; RecordingPen&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-control z-flow z-python&quot;&gt;except&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-exception z-python&quot;&gt; ImportError&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-control z-flow z-python&quot;&gt; as&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; e&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-function z-builtin z-python&quot;&gt;    print&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-string z-python&quot;&gt;f&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&amp;quot;Import error: &lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-format z-placeholder z-other z-python&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;e&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-format z-placeholder z-other z-python&quot;&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    sys&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;exit&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;1&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-python&quot;&gt;def&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; analyze_font_glyphs&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt;font_path&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;):&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;    &amp;quot;&amp;quot;&amp;quot;フォントファイルを分析して空のグリフとスペースグリフを区別する&amp;quot;&amp;quot;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    font&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt; TTFont&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;font_path&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    cmap&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; font&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;getBestCmap&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-control z-flow z-python&quot;&gt;    if&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;#39;CFF &amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-logical z-python&quot;&gt; in&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; font&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;        cff&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-indexed-name z-python&quot;&gt; font&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;CFF &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;        charstrings&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; cff&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-indexed-name z-python&quot;&gt;cff&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;0&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;].&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;CharStrings&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-control z-flow z-python&quot;&gt;    else&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-function z-builtin z-python&quot;&gt;        print&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;This is not a CFF font&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-control z-flow z-python&quot;&gt;        return&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    hmtx&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-indexed-name z-python&quot;&gt; font&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;hmtx&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    results&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; []&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    space_codes&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;0x&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;0020&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt; 0x&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;3000&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;  # SPACE, IDEOGRAPHIC SPACE&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-control z-flow z-python&quot;&gt;    for&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; unicode_code&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; glyph_name&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-control z-flow z-python&quot;&gt; in&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-builtin z-python&quot;&gt; sorted&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;cmap&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;items&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;()):&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-control z-flow z-python&quot;&gt;        if&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; glyph_name&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-logical z-python&quot;&gt; in&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; hmtx&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;metrics&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;            width&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; lsb&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; hmtx&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-indexed-name z-python&quot;&gt;metrics&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-item-access z-python&quot;&gt;glyph_name&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-control z-flow z-python&quot;&gt;        else&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;            width&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; lsb&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 0&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-control z-flow z-python&quot;&gt;        if&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; glyph_name&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-logical z-python&quot;&gt; in&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; charstrings&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;            charstring&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-indexed-name z-python&quot;&gt; charstrings&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-item-access z-python&quot;&gt;glyph_name&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;            pen&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt; RecordingPen&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-control z-flow z-python&quot;&gt;            try&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;                charstring&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;draw&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;pen&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;                commands&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; pen&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;value&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;                has_drawing&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-builtin z-python&quot;&gt; len&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;commands&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; &amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-control z-flow z-python&quot;&gt;            except&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-exception z-python&quot;&gt; Exception&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;                has_drawing&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language z-python&quot;&gt; False&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;            # グリフの分類&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;            is_space_char&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; unicode_code&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-logical z-python&quot;&gt; in&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; space_codes&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-control z-flow z-python z-keyword z-operator z-logical z-python&quot;&gt;            if not&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; has_drawing&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-control z-flow z-python&quot;&gt;                if&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; width&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; &amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 0&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-control z-flow z-python&quot;&gt;                    if&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; is_space_char&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;                        glyph_type&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;SPACE&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-control z-flow z-python&quot;&gt;                    else&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;                        glyph_type&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;BLANK_WITH_WIDTH&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-control z-flow z-python&quot;&gt;                else&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;                    glyph_type&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;EMPTY&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-control z-flow z-python&quot;&gt;            else&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;                glyph_type&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;NORMAL&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;            results&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;append&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;({&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;                &amp;#39;unicode&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-string z-python&quot;&gt; f&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&amp;quot;U+&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-format z-placeholder z-other z-python&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;unicode_code&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;:04X&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-format z-placeholder z-other z-python&quot;&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;                &amp;#39;code&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt; unicode_code&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;                &amp;#39;char&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-builtin z-python&quot;&gt; chr&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;unicode_code&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;                &amp;#39;glyph_name&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt; glyph_name&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;                &amp;#39;type&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt; glyph_type&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;                &amp;#39;width&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt; width&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;                &amp;#39;commands_count&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-builtin z-python&quot;&gt; len&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;commands&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-control z-flow z-python&quot;&gt; if&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt; has_drawing&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-control z-flow z-python&quot;&gt; else&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 0&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;            })&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-control z-flow z-python&quot;&gt;    return&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; results&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;判定基準は、次の通りです。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;NORMAL: 描画データがあるグリフ&lt;&#x2F;li&gt;
&lt;li&gt;SPACE: スペース文字（U+0020, U+3000）で描画データなし&lt;&#x2F;li&gt;
&lt;li&gt;BLANK_WITH_WIDTH: スペース以外で幅はあるが描画データなし → 削除対象&lt;&#x2F;li&gt;
&lt;li&gt;EMPTY: 幅や描画データがない → 削除対象&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;自動修正スクリプト&quot;&gt;自動修正スクリプト&lt;&#x2F;h3&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;python&quot; data-name=&quot;font_cleaner_final.py&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-python&quot;&gt;def&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; fix_font_cmap_only&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt;input_path&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt; output_path&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;):&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;    &amp;quot;&amp;quot;&amp;quot;OTEで作成されたフォントのcmapテーブルから空グリフエントリを削除&amp;quot;&amp;quot;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    font&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt; TTFont&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;input_path&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    original_cmap&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; font&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;getBestCmap&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-control z-flow z-python&quot;&gt;    if&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;#39;CFF &amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-logical z-python&quot;&gt; in&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; font&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;        cff&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-indexed-name z-python&quot;&gt; font&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;CFF &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;        charstrings&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; cff&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-indexed-name z-python&quot;&gt;cff&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;0&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;].&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;CharStrings&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-control z-flow z-python&quot;&gt;    else&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-control z-flow z-python&quot;&gt;        return&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language z-python&quot;&gt; False&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    hmtx&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-indexed-name z-python&quot;&gt; font&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;hmtx&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    codes_to_remove&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; []&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    space_code&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt; 0x&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;0020&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    ideographic_space_code&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt; 0x&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;3000&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-control z-flow z-python&quot;&gt;    for&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; unicode_code&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; glyph_name&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-control z-flow z-python&quot;&gt; in&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; original_cmap&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;items&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;():&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-control z-flow z-python&quot;&gt;        if&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; glyph_name&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-logical z-python&quot;&gt; in&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; hmtx&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;metrics&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;            width&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; lsb&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; hmtx&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-indexed-name z-python&quot;&gt;metrics&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-item-access z-python&quot;&gt;glyph_name&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-control z-flow z-python&quot;&gt;        else&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;            width&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; lsb&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 0&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-control z-flow z-python&quot;&gt;        if&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; glyph_name&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-logical z-python&quot;&gt; in&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; charstrings&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;            charstring&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-indexed-name z-python&quot;&gt; charstrings&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-item-access z-python&quot;&gt;glyph_name&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;            pen&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt; RecordingPen&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-control z-flow z-python&quot;&gt;            try&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;                charstring&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;draw&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;pen&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;                commands&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; pen&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;value&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;                has_drawing&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-builtin z-python&quot;&gt; len&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;commands&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; &amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-control z-flow z-python&quot;&gt;            except&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-exception z-python&quot;&gt; Exception&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;                has_drawing&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language z-python&quot;&gt; False&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;            # スペース文字以外で描画データがない場合は削除対象&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-control z-flow z-python&quot;&gt;            if&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; unicode_code&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-logical z-python&quot;&gt; not in&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;space_code&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; ideographic_space_code&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-control z-flow z-python z-keyword z-operator z-logical z-python&quot;&gt;                if not&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; has_drawing&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-logical z-python&quot;&gt; and&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; width&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; &amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 0&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;                    codes_to_remove&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;append&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;unicode_code&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;    # cmapテーブルから削除&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-control z-flow z-python&quot;&gt;    for&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; table&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-control z-flow z-python&quot;&gt; in&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-indexed-name z-python&quot;&gt; font&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;cmap&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;].&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;tables&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-control z-flow z-python&quot;&gt;        if&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-builtin z-python&quot;&gt; hasattr&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;table&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;#39;cmap&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;):&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-control z-flow z-python&quot;&gt;            for&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; code&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-control z-flow z-python&quot;&gt; in&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; codes_to_remove&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-control z-flow z-python&quot;&gt;                if&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; code&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-logical z-python&quot;&gt; in&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; table&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;cmap&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-control z-flow z-python&quot;&gt;                    del&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; table&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-indexed-name z-python&quot;&gt;cmap&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-item-access z-python&quot;&gt;code&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    font&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;save&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;output_path&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-control z-flow z-python&quot;&gt;    return&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language z-python&quot;&gt; True&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-builtin z-python&quot;&gt; len&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;codes_to_remove&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;修正結果&quot;&gt;修正結果&lt;&#x2F;h2&gt;
&lt;p&gt;修正結果は次の通りです。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;総cmapエントリ数: 10,161 → 5,762個（削減率: 43.3%）&lt;&#x2F;li&gt;
&lt;li&gt;削除されたエントリ: 4,399個&lt;&#x2F;li&gt;
&lt;li&gt;Adobe Japan 1-4拡張範囲: 408個&lt;&#x2F;li&gt;
&lt;li&gt;その他の範囲: 3,991個&lt;&#x2F;li&gt;
&lt;li&gt;ファイルサイズ: 2.6% 削減&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;修正の結果、
今のところターミナルでも問題なく使用できています。&lt;&#x2F;p&gt;
&lt;p&gt;上記のスクリプトは精緻にテストを行なっていませんので、
利用については自己責任でどうぞ。&lt;&#x2F;p&gt;
</content>
        <summary type="html">フォント編集ソフト「OTEdit」で作成されたフォントの空グリフ問題について解説。Adobe-Japan1文字集合選択時に発生する空グリフによりフォールバック機能が正常に動作しない問題と、Pythonスクリプトを使った修正方法を紹介。</summary>
        </entry><entry xml:lang="en">
        <title>Amazon AmplifyのNode.jsバージョンアップ対応</title>
        <published>2025-09-14T00:00:00+00:00</published>
        <updated>2025-09-14T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2025/09/amazon-amplify-node-versionup/" type="text/html"/>
        <id>https://codedchords.dev/blog/2025/09/amazon-amplify-node-versionup/</id>
        
            <content type="html">&lt;p&gt;I recieved the following email from AWS.&lt;&#x2F;p&gt;
&lt;p&gt;This blog does indeed use Amazon Amplify, but I thought it would be fine since I hadn&#x27;t specified a Node.js version and the default was being used.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;2025 年 9 月 15 日から、AWS Amplify コンソールは Node.js 14、Node.js 16、Node.js 18 のサポートを終了します。この日を過ぎると、Node バージョンをアップグレードするまでアプリケーションへの更新をデプロイできなくなります。2025 年 9 月 15 日までに、Node.js 14、Node.js 16、Node.js 18 を使用するすべてのアプリケーションを Node.js 20 以降に更新してください。&lt;&#x2F;p&gt;
&lt;p&gt;Node.js 14、Node.js 16、Node.js 18 ですでにデプロイされているアプリケーションは引き続き実行され、更新をデプロイする必要がない限り影響はありません。&lt;&#x2F;p&gt;
&lt;p&gt;アップグレードする前に新しいブランチでアプリケーションをテストして、すべての機能が正常に動作することを確認することをお勧めします。移行ガイドラインについては、[1] ページの「アプリケーションの Node.js バージョンを更新する必要がある」セクションを参照してください。&lt;&#x2F;p&gt;
&lt;p&gt;影響を受けるリソースのリストは、AWS ヘルスダッシュボードの「影響を受けるリソース」タブにあります。&lt;&#x2F;p&gt;
&lt;footer&gt;
    AWS 通知メール『AWS Amplify は、2025 年 9 月 15 日をもって Node.js 14&#x2F;16&#x2F;18 ベースのアプリのサポートを終了します』
    &lt;&#x2F;footer&gt;
  &lt;&#x2F;blockquote&gt;
&lt;p&gt;Just to be sure, I checked the Node version and found that Node 18 was being used. That&#x27;s no good.
Let&#x27;s explicitly specify the version and rebuild.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;yaml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;version&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;frontend&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;  phases&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;    preBuild&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;      commands&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;        # Node.jsバージョンを24に指定（ローカルのMacと同じ）&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;        -&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; nvm use 24&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;        # バージョン確認（ログに出力）&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;        -&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; node --version&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;        -&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; npm --version&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;        # .envを削除&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;        -&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; rm -f .env&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;        -&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; npm ci --cache .npm --prefer-offline&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;        # 環境変数を.envファイルに出力&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;        -&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; echo &amp;quot;NEXT_PUBLIC_SITE_URL=https:&#x2F;&#x2F;blog.yostos.org&amp;quot; &amp;gt;&amp;gt; .env&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;        (中略)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;    build&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;      commands&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;        -&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; npm run build&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;  artifacts&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;    baseDirectory&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; .next&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;    files&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;      -&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;#39;**&#x2F;*&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;  cache&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;    paths&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;      -&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; .next&#x2F;cache&#x2F;**&#x2F;*&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;      -&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; .npm&#x2F;**&#x2F;*&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;</content>
        <summary type="html">2025年9月15日からAWS AmplifyがNode.js 14&#x2F;16&#x2F;18のサポートを終了するため、Node.js 24に更新した記録です。</summary>
        </entry><entry xml:lang="en">
        <title>TypePad終了：ブログ革命の一時代の終焉</title>
        <published>2025-09-09T00:00:00+00:00</published>
        <updated>2025-09-09T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2025/09/typepad-shutdown-end-of-blog-era/" type="text/html"/>
        <id>https://codedchords.dev/blog/2025/09/typepad-shutdown-end-of-blog-era/</id>
        
            <content type="html">&lt;!-- textlint-disable --&gt;
&lt;img
  src=&quot;https:&amp;#x2F;&amp;#x2F;codedchords.dev&amp;#x2F;blog&amp;#x2F;2025&amp;#x2F;09&amp;#x2F;typepad-shutdown-end-of-blog-era&amp;#x2F;typepad.webp?h=600eb06e08c28be163be&quot;
  alt=&quot;Typepad&quot; width=&quot;1562&quot; height=&quot;992&quot; loading=&quot;lazy&quot;
&#x2F;&gt;&lt;!-- textlint-enable --&gt;
&lt;!-- textlint-disable ja-technical-writing&#x2F;sentence-length --&gt;
&lt;details&gt;
&lt;summary&gt;Table of Contents&lt;&#x2F;summary&gt;
&lt;!-- toc --&gt;
&lt;&#x2F;details&gt;
&lt;p&gt;An article titled &quot;Typepad is shutting down&quot; has been published on TypePad&#x27;s official blog (the site has since been shut down).&lt;&#x2F;p&gt;
&lt;blockquote&gt;
We have made the difficult decision to discontinue Typepad, effective September 30, 2025.
&lt;p&gt;&lt;strong&gt;What Does This Mean for You?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;After September 30, 2025, access to Typepad – including account management, blogs, and all associated content – will no longer be available. Your account and all related services will be permanently deactivated.&lt;&#x2F;p&gt;
&lt;footer&gt;
  &lt;cite&gt;Everything Typepad - &quot;Typepad is shutting down&quot;&lt;&#x2F;cite&gt;
&lt;&#x2F;footer&gt;
&lt;&#x2F;blockquote&gt;
&lt;h2 id=&quot;An_Icon_of_Early_Blog_Culture&quot;&gt;An Icon of Early Blog Culture&lt;&#x2F;h2&gt;
&lt;p&gt;TypePad launched in October 2003, and I registered and started using it almost simultaneously with the service launch. This was back when Six Apart&#x27;s Japanese subsidiary hadn&#x27;t even been established yet.&lt;&#x2F;p&gt;
&lt;p&gt;Looking back at the situation then, PC magazines featured articles on how to set up Movable Type, but it was still an era with high technical barriers where only tech-savvy enthusiasts would set up their own servers.&lt;&#x2F;p&gt;
&lt;p&gt;Around that time, I read Rebecca Blood&#x27;s &quot;Weblog: A History and Perspective&quot; (2000) and thought, &quot;Wow, this is something different from Japanese diary sites.&quot; It was also impressive that she consistently used the term &quot;weblog&quot; throughout that period.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;Constraints_That_Sparked_Creative_Exploration&quot;&gt;Constraints That Sparked Creative Exploration&lt;&#x2F;h2&gt;
&lt;p&gt;One of TypePad&#x27;s charms was the joy of exercising creativity within a constrained environment. Creating widget-like components for the sidebar, customizing designs within limited freedom—it was truly experiencing the essence of blogging.&lt;&#x2F;p&gt;
&lt;p&gt;Unlike today&#x27;s web development environment where you can do anything, there was a kind of creativity that emerged precisely because of certain constraints.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;Meeting_the_Developer_Couple&quot;&gt;Meeting the Developer Couple&lt;&#x2F;h2&gt;
&lt;p&gt;On November 21, 2003, I participated in a Six Apart gathering held in Tokyo and had the memorable experience of meeting the developers Ben Trott and Mena Trott in person, which remains vivid in my memory.&lt;&#x2F;p&gt;
&lt;p&gt;Around this time, Six Apart was scaling up their service after receiving funding from venture capital led by Joi Ito&#x27;s Neoteny Co. At the venue, I was able to meet various people who participated as TypePad users—Neoteny associates, people from NTT Communications, someone who challenges the human-powered aircraft contest every year—and could feel firsthand the excitement of the early blog community.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;The_Evolution_of_Blog_Culture_and_Personal_Publishing&quot;&gt;The Evolution of Blog Culture and Personal Publishing&lt;&#x2F;h2&gt;
&lt;p&gt;TypePad&#x27;s shutdown feels like it symbolizes the end of an era, beyond just a service termination.&lt;&#x2F;p&gt;
&lt;p&gt;In 2003, it was also a transitional period when the abbreviation &quot;blog&quot; was trying to replace &quot;weblog.&quot; The term &quot;blog,&quot; which originated from Peter Merholz&#x27;s split notation &quot;we blog&quot; in 1999, became mainstream around this time.&lt;&#x2F;p&gt;
&lt;p&gt;The blog community of that era had a culture of writing deeper content and engaging in denser communication, unlike today&#x27;s SNS-dominated age. There were rich interactions that we don&#x27;t see today, such as inter-article linking through TrackBack and active discussions in comment sections.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;The_Importance_of_Personal_Ownership:_From_Dawn_to_Present&quot;&gt;The Importance of Personal Ownership: From Dawn to Present&lt;&#x2F;h2&gt;
&lt;p&gt;When I think about it, the dawn of blogging—the early 2000s when TypePad and Movable Type appeared—was very similar to the ideals advocated by current IndieWeb and microblog concepts, wasn&#x27;t it?&lt;&#x2F;p&gt;
&lt;p&gt;Back then, many people ran blogs on their own domains, and personal publishing on platforms you owned and managed was taken for granted. In the pre-Twitter and Facebook web world, the principle of &quot;personal publishing on your own blog&quot; was practiced unconsciously.&lt;&#x2F;p&gt;
&lt;p&gt;Regarding the microblog concept advocated by the IndieWeb movement, while I personally question whether micro-web is necessary, I strongly resonate with the underlying idea that &quot;individuals should have a place where they can control their own publishing.&quot;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;Current_Choice:_Self-Built_Blog_Based_on_Next.js&quot;&gt;Current Choice: Self-Built Blog Based on Next.js&lt;&#x2F;h2&gt;
&lt;p&gt;With such thinking, I currently operate a self-built blog based on Next.js on my own domain&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-1-1&quot;&gt;&lt;a href=&quot;#fn-1&quot;&gt;1&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;. This is one answer I&#x27;ve reached through a long evolution of personal web usage from TypePad.&lt;&#x2F;p&gt;
&lt;p&gt;From TypePad era&#x27;s &quot;creativity within constraints,&quot; through Blogger and Static Site Generators&#x27; &quot;freedom and management complexity,&quot; to now choosing &quot;complete technical autonomy.&quot; In terms of avoiding platform dependency risks and building an environment where I can control my own publishing, this could be seen as a return to the spirit of early blogging days.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;The_Fragility_and_Inheritance_of_Digital_Culture&quot;&gt;The Fragility and Inheritance of Digital Culture&lt;&#x2F;h2&gt;
&lt;p&gt;TypePad&#x27;s termination reminds us once again of the vulnerability of cultural assets in the digital age. The reality that a platform that supported many people&#x27;s thoughts and creativity for 22 years can completely disappear with a single corporate decision.&lt;&#x2F;p&gt;
&lt;p&gt;This reality tells the story of the importance of individuals owning their own publishing infrastructure. Platforms may disappear, but domains and content you manage yourself continue to exist.&lt;&#x2F;p&gt;
&lt;p&gt;At the same time, the role TypePad played—making it technically possible for ordinary people to publish online and promoting the democratization of blog culture—can be said to be inherited as the foundation for current SNS and content platforms, as well as new web technologies.&lt;&#x2F;p&gt;
&lt;p&gt;Personal publishing environments may be drawing a large circle, going from hosted blogs to SNS, and then returning to individual ownership again.&lt;&#x2F;p&gt;
&lt;p&gt;Though it&#x27;s the flow of time, it&#x27;s still quite sad.&lt;&#x2F;p&gt;
&lt;!-- textlint-enable ja-technical-writing&#x2F;sentence-length --&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;TypePadの公式ブログに「Typepad is shutting down」という記事が掲載されました（サイトは閉鎖済み）。&lt;&#x2F;p&gt;
&lt;blockquote&gt;
We have made the difficult decision to discontinue Typepad, effective September 30, 2025.
&lt;p&gt;&lt;strong&gt;What Does This Mean for You?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;After September 30, 2025, access to Typepad – including account management, blogs, and all associated content – will no longer be available. Your account and all related services will be permanently deactivated.&lt;&#x2F;p&gt;
&lt;footer&gt;
  &lt;cite&gt;Everything Typepad - &quot;Typepad is shutting down&quot;&lt;&#x2F;cite&gt;
&lt;&#x2F;footer&gt;
&lt;&#x2F;blockquote&gt;
## 初期ブログ文化の象徴的存在
&lt;p&gt;TypePadは2003年10月にローンチされ、私もサービス開始とほぼ同時にユーザー登録して利用を始めました。まだSix Apartの日本法人も設立されていない頃の話です。&lt;&#x2F;p&gt;
&lt;p&gt;当時の状況を振り返ると、パソコン系雑誌でMovable Typeの導入方法が特集記事として掲載されていましたが、それでもまだまだマニアックな人たちがサーバーを立ち上げるという、技術的ハードルの高い時代でした。&lt;&#x2F;p&gt;
&lt;p&gt;ちょうどその頃、Rebecca Bloodの「Weblog: A History and Perspective」（2000年）を読んで、「おおぉ、これは日本の日記サイトとは別物なんだな」と感じていました。彼女は当時、一貫して「weblog」という用語を使用し続けていたことも印象的でした。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;デザインへの探求心を刺激した制約&quot;&gt;デザインへの探求心を刺激した制約&lt;&#x2F;h2&gt;
&lt;p&gt;TypePadの魅力の1つは、制限された環境の中でいかに創造性を発揮するかという楽しさでした。サイドバーに置くウィジェット的な部品を作ったり、限られた自由度の中でデザインをカスタマイズしたりと、まさにブログの醍醐味を味わっていました。&lt;&#x2F;p&gt;
&lt;p&gt;現在のように何でもできるWebサイト制作環境とは違い、ある種の制約があったからこそ生まれる創造性があったのかもしれません。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;開発者夫妻との出会い&quot;&gt;開発者夫妻との出会い&lt;&#x2F;h2&gt;
&lt;p&gt;2003年11月21日、東京で開催されたSix Apartのギャザリングに参加し、開発者であるBen TrottとMena Trott夫妻に直接お会いできたことは、今でも印象深い体験として記憶に残っています。&lt;&#x2F;p&gt;
&lt;p&gt;この頃、Six ApartはJoi ItoのNeoteny Co.主導のベンチャーキャピタルから資金調達を受けてサービスを本格化させていました。会場ではTypePadユーザーとして参加していた様々な方々—Neotenyの関係者、NTT Communicationsの方、毎年鳥人間コンテストにチャレンジされている方など—とも知り合うことができ、初期のブログコミュニティの熱気を肌で感じることができました。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;ブログ文化の変遷と個人発信の意味&quot;&gt;ブログ文化の変遷と個人発信の意味&lt;&#x2F;h2&gt;
&lt;p&gt;TypePadのシャットダウンは、単なるサービス終了を超えて、1つの時代の終わりを象徴しているように感じます。&lt;&#x2F;p&gt;
&lt;p&gt;2003年当時、「blog」という略語が「weblog」に取って代わろうとしていた過渡期でもありました。Peter Merholzが1999年に「we blog」と分割表記したのが始まりとされる「blog」という呼び方が、ちょうどこの頃に一般化していったのです。&lt;&#x2F;p&gt;
&lt;p&gt;当時のブログ界隈は、今のSNS全盛時代とは異なり、より深い文章を書き、より密なコミュニケーションを取る文化がありました。TrackBackによる記事間のリンクや、コメント欄での活発な議論など、現在では見られないような濃密な交流が日常的に行われていたのです。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;個人所有の重要性：黎明期から現在へ&quot;&gt;個人所有の重要性：黎明期から現在へ&lt;&#x2F;h2&gt;
&lt;p&gt;よく考えてみると、ブログの黎明期—TypePadやMovable Typeが登場した2000年代初頭—は、現在のIndieWebやマイクロブログ・コンセプトが提唱する理念に非常に近い状況だったのではないでしょうか。&lt;&#x2F;p&gt;
&lt;p&gt;当時は多くの人が自分自身のドメインでブログを運営し、個人の発信は自身が所有・管理する場所で行うことが当たり前でした。TwitterやFacebookが台頭する以前のWeb世界では、「個人の発信は自身の所有するブログで」という原則が、意識せずとも実践されていたのです。&lt;&#x2F;p&gt;
&lt;p&gt;IndieWebムーブメントが主張するマイクロブログのコンセプトについては、個人的にマイクロWebが必要かどうかは議論の余地があるものの、その根底にある「個人が自分の発信をコントロールできる場所を持つ」という考え方には強く共感しています。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;現在の選択：Next.jsベースの自作ブログ&quot;&gt;現在の選択：Next.jsベースの自作ブログ&lt;&#x2F;h2&gt;
&lt;p&gt;そうした考えもあって、私は現在、自身が所有するドメインでNext.jsをベースとした自作のブログを運営しています&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-2-1&quot;&gt;&lt;a href=&quot;#fn-2&quot;&gt;2&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;。これは、TypePadからの長い個人Web利用の変遷を経て到達した、ひとつの回答でもあります。&lt;&#x2F;p&gt;
&lt;p&gt;TypePad時代の「制約の中での創造性」から、BloogerやStatic Site Generatorでの「自由度と管理の複雑さ」を経て、現在は「技術的完全自律性」を選択したという流れ。プラットフォーム依存のリスクを避け、自分の発信を自分でコントロールできる環境を構築するという意味では、まさに初期ブログ時代の精神への回帰とも言えるかもしれません。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;デジタル文化の儚さと継承&quot;&gt;デジタル文化の儚さと継承&lt;&#x2F;h2&gt;
&lt;p&gt;TypePadの終了は、デジタル時代における文化的資産の脆弱性をあらためて思い起こさせます。22年間という長期間にわたって多くの人々の思考と創造性を支えてきたプラットフォームが、企業の判断1つで完全に消失してしまうという現実。&lt;&#x2F;p&gt;
&lt;p&gt;この現実こそが、個人が自分の発信基盤を所有することの重要性を物語っています。プラットフォームは消えても、自分が管理するドメインとコンテンツは残り続けるのです。&lt;&#x2F;p&gt;
&lt;p&gt;同時に、TypePadが果たした役割—一般の人々がオンラインで発信することを技術的に可能にし、ブログ文化の民主化を推進したこと—は現在のSNSやコンテンツプラットフォーム、新しいWeb技術の基盤となって受け継がれているとも言えるでしょう。&lt;&#x2F;p&gt;
&lt;p&gt;個人の発信環境は、ホスト型ブログからSNSへ、そして再び個人所有へと回帰する大きな円を描いているのかもしれません。&lt;&#x2F;p&gt;
&lt;p&gt;時代の流れとは言え、やはり寂しい限りです。&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;&lt;em&gt;参考：TypePadは2025年9月30日をもってサービス終了予定。コンテンツのエクスポートは同日までに完了する必要があります。&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;section class=&quot;footnotes&quot;&gt;
&lt;ol class=&quot;footnotes-list&quot;&gt;
&lt;li id=&quot;fn-1&quot;&gt;
&lt;p&gt;I&#x27;ve moved to Zola in 2026. &lt;a href=&quot;#fr-1-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li id=&quot;fn-2&quot;&gt;
&lt;p&gt;2026年にZolaへ移行しました。 &lt;a href=&quot;#fr-2-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;&#x2F;section&gt;
</content>
        <summary type="html">TypePadが2025年9月30日でサービス終了。2003年から22年間続いたブログプラットフォームの歴史を振り返り、初期ブログ文化からSNS時代、そして個人所有メディアへの回帰まで、Web発信環境の変遷を考察。</summary>
        </entry><entry xml:lang="en">
        <title>A New Proposal for the Cloud Era: How UGREEN NAS is changing the future of personal data storage</title>
        <published>2025-08-31T00:00:00+00:00</published>
        <updated>2025-08-31T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2025/08/ugreen-nas/" type="text/html"/>
        <id>https://codedchords.dev/blog/2025/08/ugreen-nas/</id>
        
            <content type="html">&lt;!-- textlint-disable --&gt;
&lt;img
  src=&quot;https:&amp;#x2F;&amp;#x2F;codedchords.dev&amp;#x2F;blog&amp;#x2F;2025&amp;#x2F;08&amp;#x2F;ugreen-nas&amp;#x2F;ugreen-nas.webp?h=9118045f14051f5966ab&quot;
  alt=&quot;UGREEN NAS&quot; width=&quot;740&quot; height=&quot;467&quot; loading=&quot;lazy&quot;
&#x2F;&gt;&lt;!-- textlint-enable --&gt;
&lt;details&gt;
&lt;summary&gt;Table of Contents&lt;&#x2F;summary&gt;
&lt;!-- toc --&gt;
&lt;&#x2F;details&gt;
&lt;h2 id=&quot;Why_I_Chose_UGREEN_NAS&quot;&gt;Why I Chose UGREEN NAS&lt;&#x2F;h2&gt;
&lt;p&gt;Among numerous NAS products, I selected the UGREEN NASync DXP2800
for its outstanding cost-performance ratio.
Despite being significantly cheaper than the Synology DS224+,
it comes standard with an Intel N100 processor and 8GB DDR5 memory.
It also includes a 2.5GbE port and dual M.2 slots.
The 2.5GbE port is particularly rare in this price range and offers
future-proofing.&lt;&#x2F;p&gt;
&lt;p&gt;The tool-free removable drive tray system for easy HDD
replacement was also appealing. Setup Experience Upon unboxing, I was
impressed by the build quality of the aluminum alloy chassis. The included
dual CAT 7 LAN cables were also high-quality. I installed
2×&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;amzn.to&#x2F;4myLddI&quot;&gt;WD Red Plus 4TB HDDs&lt;&#x2F;a&gt; (RAID 1 configuration) and
2×&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;amzn.to&#x2F;3HZmdgD&quot;&gt;Samsung 990 EVO Plus 1TB SSDs&lt;&#x2F;a&gt;.
HDDs simply clicked into the trays, and SSDs were easily installed with the included
screwdriver. Initial setup through the dedicated &quot;UGREEN NAS&quot; app took just
minutes. The RAID configuration suggested optimal settings based on
installed drives, making it beginner-friendly without confusion.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;Real-World_Usage&quot;&gt;Real-World Usage&lt;&#x2F;h2&gt;
&lt;p&gt;The Samsung SSD cache implementation showed dramatic results, with
near-instantaneous photo browsing and previews. It&#x27;s a completely different
experience from external HDDs. Power management features allow scheduled
automatic shutdown at night and startup in the morning, extending HDD
lifespan. UGOS (UGREEN&#x27;s OS) exceeded expectations with robust file
management, automatic photo organization, remote access, and other essential
daily functions.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;Final_Verdict:_Worth_Buying?&quot;&gt;Final Verdict: Worth Buying?&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;strong&gt;Conclusion: Absolutely a &quot;buy.&quot;&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;The price-to-hardware spec ratio is unmatched by competitors. It
combines beginner-friendly usability with future expandability.
Considerations:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Security concerns about Chinese manufacturers (may not suit corporate
secrets)&lt;&#x2F;li&gt;
&lt;li&gt;Software is still developing compared to Synology DSM&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;However, it&#x27;s sufficient for home use and continuously improving through
frequent updates. Compared to monthly cloud service fees, the long-term
benefits of building a private cloud are immeasurable. I recommend this
noteworthy product that&#x27;s bringing fresh innovation to the NAS market.&lt;&#x2F;p&gt;
</content>
        <summary type="html">A 2-month review of the excellent cost-performance UGREEN NASync DXP2800. This popular NAS offers outstanding specs for its price range. From tool-free easy setup and SSD cache acceleration to UGOS practicality, we explain in detail why we recommend it to NAS beginners and how to use it effectively. We provide an honest evaluation including concerns about Chinese manufacturers.</summary>
        </entry><entry xml:lang="en">
        <title>Claude Proに週間利用制限が導入へ - 2025年8月28日から</title>
        <published>2025-07-29T00:00:00+00:00</published>
        <updated>2025-07-29T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2025/07/claude-pro-weekly-usage-limits/" type="text/html"/>
        <id>https://codedchords.dev/blog/2025/07/claude-pro-weekly-usage-limits/</id>
        
            <content type="html">&lt;details&gt;
&lt;summary&gt;Table of Contents&lt;&#x2F;summary&gt;
&lt;!-- toc --&gt;
&lt;&#x2F;details&gt;
&lt;p&gt;2025年7月28日、AnthropicからClaude Proユーザー向けに「Important updates to your Pro account usage limits」というタイトルのメールが配信されました。このメールでは、2025年8月28日から導入される新しい週間利用制限について詳細が説明されています。本記事では、この変更内容と背景について解説します。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;変更内容の概要&quot;&gt;変更内容の概要&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;strong&gt;Claude Code&lt;&#x2F;strong&gt;&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-1-1&quot;&gt;&lt;a href=&quot;#fn-1&quot;&gt;1&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt; の使用制限は、今後は以下のように追加されます。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;5時間ごとにリセットされる利用制限（従来通り）&lt;&#x2F;li&gt;
&lt;li&gt;7日ごとにリセットされる全体的な週間制限（新規追加）&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;&lt;strong&gt;Claude Opus 4&lt;&#x2F;strong&gt; についても、これまで明示的な週間制限はありませんでしたが、7日ごとにリセットされる専用の週間制限が新設されます。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;影響予測&quot;&gt;影響予測&lt;&#x2F;h2&gt;
&lt;p&gt;Anthropicでは、現在の利用パターンに基づき影響を受けるユーザーは全体の5％未満とされており、大多数のユーザーは違いを感じることはないとのことです。&lt;&#x2F;p&gt;
&lt;p&gt;Proユーザーは週間制限内でSonnet 4を週あたり40-80時間利用可能とされていますが、この時間はコードベースのサイズや自動承認モードなどのユーザー設定により変動します。また、複数のClaude Codeインスタンスを同時実行するユーザーは、より早く制限に到達する可能性があります。&lt;&#x2F;p&gt;
&lt;p&gt;私自身は先月までMAXプランを試していて、Claude Codeを使い倒しており、Proにダウングレードしてからは集中して作業するとやはり制限に達してしまいます。Proユーザーでもなお、Claude Codeを利用しているユーザーがそれほど多くないため上記の予測になっているのかも知れません。実際にClaude Codeを使っていると、ちょっと制限を考慮して作業計画する必要がありそうです。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;制限導入の背景&quot;&gt;制限導入の背景&lt;&#x2F;h2&gt;
&lt;p&gt;Claude Code、特にサブスクリプション・バンドルの一部として、前例のない成長を遂げています。この急激な成長により、システム容量に予想以上の負荷がかかっている状況のようです。Claude Codeを使ってみるとわかりますが、一気に活用度も上がるのでこういった状況になるのは容易に想像できます。&lt;&#x2F;p&gt;
&lt;p&gt;合わせて以下のような問題も発生しているようです。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;少数のユーザーによるアカウント共有やアクセス転売などのポリシー違反&lt;&#x2F;li&gt;
&lt;li&gt;Claudeを24時間365日バックグラウンドで実行するような極端な利用パターン&lt;&#x2F;li&gt;
&lt;li&gt;200ドルのプランで数万ドル相当のモデル使用量を消費するような極端なケース&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;これらの問題により、全ユーザーのシステム容量に影響が生じており、限られたコンピューティングリソースの問題に直面しています。これは最近多くのAIプラットフォーム（ReplitやAnysphereなど）が抱えている共通の課題でもあります。&lt;&#x2F;p&gt;
&lt;p&gt;Anthropicは、メールの中で「この同じ期間中に、ユーザーがいくつかの信頼性とパフォーマンスの問題に遭遇したことを認識している」と述べています。これらの問題は、システム容量の逼迫と関連している可能性があり、同社は「これらをできるだけ迅速に修正するために取り組んでおり、今後数日から数週間にわたって残りの問題に対処し続ける」としています。実際、7月中旬頃から、Claude Codeユーザーが予期せず制限的な利用制限に直面する問題が発生していました。&lt;&#x2F;p&gt;
&lt;p&gt;Anthropicは今回の新しい利用制限により、アカウント共有や転売などのポリシー違反への対処、24時間365日のバックグラウンド実行による過度な利用の抑制、そして全ユーザーに対するより公平で信頼性の高いサービス提供を目指しています。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;影響を受けるユーザーへの対応方法&quot;&gt;影響を受けるユーザーへの対応方法&lt;&#x2F;h2&gt;
&lt;p&gt;週間制限の影響を受ける可能性のあるユーザーは、以下の対応を検討できます。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;利用パターンの見直し&lt;&#x2F;strong&gt;：並行実行を避けたり、利用時間の分散など効率的な利用を心がける&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;サブスクリプションの管理&lt;&#x2F;strong&gt;：必要に応じて一時的にMAXプランへの変更を行なう&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;代替オプションの検討&lt;&#x2F;strong&gt;：Claude Codeに過度に負荷をかけない作業パターンを検討する&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;私自身が最近行なっているのは、次のような対応です。&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;いきなりClaude Codeを使うのでなく、事前に&lt;code&gt;Claude.md&lt;&#x2F;code&gt;で開発方針やアーキテクチャー、コードの構成、使用フレームワーク、テスト方針、テストフレームワークなど細かく記載しておく&lt;&#x2F;li&gt;
&lt;li&gt;問題が発生した時は、Claude Codeに拘って解決するのでなく、一旦状況を整理して&lt;code&gt;Claude.md&lt;&#x2F;code&gt;に記載させる。その後、問題の解決方法を練って、&lt;code&gt;Claude.md&lt;&#x2F;code&gt; に対処方法を記載した上でClaude Codeに戻る&lt;&#x2F;li&gt;
&lt;li&gt;上記のいずれの作業もClaude Desktopの支援が期待できる。つまり設計はClaude Desktopとして、Claude Codeは実装に特化させるアプローチである。Claude CodeをClaude DesktopのMCPサーバーで登録しておけば、&lt;code&gt;Claude.md&lt;&#x2F;code&gt; を通してスムーズに連携できる&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;h2 id=&quot;まとめ&quot;&gt;まとめ&lt;&#x2F;h2&gt;
&lt;p&gt;Anthropicは急速な成長、ポリシー違反、極端な利用パターンによるシステム負荷の増大に対処するため、この制限導入を決定しました。大多数のユーザー（95％以上）には影響がないとされていますが、重度の利用者にとっては利用パターンの見直しが必要になる可能性があります。&lt;&#x2F;p&gt;
&lt;p&gt;今後も開発者の利用パターンを学習し、コミュニティのニーズに合わせて制限を調整していく方針が示されており、AnthropicがClaude Codeの持続可能な運営を目指していることが伺えます。&lt;&#x2F;p&gt;
&lt;section class=&quot;footnotes&quot;&gt;
&lt;ol class=&quot;footnotes-list&quot;&gt;
&lt;li id=&quot;fn-1&quot;&gt;
&lt;p&gt;Claude Codeは、Anthropicが提供する開発者向けのコマンドラインツールです。ターミナルから直接Claudeにコーディングタスクを委託できる機能です。このツールにより、開発者は複雑なコーディング作業をClaudeに任せることができ、生産性の向上が期待できます。 &lt;a href=&quot;#fr-1-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;&#x2F;section&gt;
</content>
        <summary type="html">Anthropic announced the introduction of weekly usage limits for Claude Pro users. This article explains the details and background of the new restrictions starting August 28, 2025, and response methods for affected users.(AnthropicからClaude Proユーザー向けに週間利用制限の導入が発表されました。2025年8月28日から開始される新しい制限の詳細と背景、影響を受けるユーザーへの対応方法について解説します。)</summary>
        </entry><entry xml:lang="en">
        <title>主要AI企業によるAIの理解能力喪失への警告</title>
        <published>2025-07-24T00:00:00+00:00</published>
        <updated>2025-07-24T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2025/07/ai-transparency-warning/" type="text/html"/>
        <id>https://codedchords.dev/blog/2025/07/ai-transparency-warning/</id>
        
            <content type="html">&lt;h2 id=&quot;主要AI企業による警告&quot;&gt;主要AI企業による警告&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;venturebeat.com&#x2F;&quot;&gt;VentureBeat&lt;&#x2F;a&gt;で「OpenAI, Google DeepMind and Anthropic sound alarm: &#x27;We may be losing the ability to understand AI&#x27;」&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-1-1&quot;&gt;&lt;a href=&quot;#fn-1&quot;&gt;1&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;という記事を見つけました。&lt;&#x2F;p&gt;
&lt;p&gt;内容は、OpenAI、Google DeepMind、Meta、Anthropicの40人以上の研究者が共同
で今後AIの思考を監視できなくなる可能性があるという重要な警告を発表したとい
うものです
。&lt;&#x2F;p&gt;
&lt;p&gt;現在のAIシステムは「思考の連鎖（Chain of Thought）」と呼ばれる人間が読める
言語での段階的推論過程を示すため、その思考を監視できます。しかし、この能力を
失う危険性が高まっているというのです。&lt;&#x2F;p&gt;
&lt;p&gt;通常は競合関係にある企業が団結してこの
問題に取り組んでいます。これは業界全体でこの安全性問題を深刻に受け止めている
ことを示しています。AIの透明性確保は今後の重要課題となってくると思いました
。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;どういうことなのか&quot;&gt;どういうことなのか&lt;&#x2F;h2&gt;
&lt;p&gt;現在のAIシステム（OpenAIのo1など）は複雑なタスクで「思考の連鎖（Chain of Thought）」を作業記憶として使用する必要があり、その推論過程が人間の観察者に部分的に見える状態です。これにより安全性監視が可能でした。&lt;&#x2F;p&gt;
&lt;p&gt;しかし、これが出来なくなるリスクも出てきています。その理由は次の通りです。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;これまでの言語ベースの思考でなく連続的な数学空間で推論するという新しいAIのアーキテクチャーが出てきている。これは人間からすると言語での思考を辿らず「直感」で結論に達しているようなもので、言語による思考を辿ることができない&lt;&#x2F;li&gt;
&lt;li&gt;AIが思考過程を隠ぺいする可能性がある。これは悪意でなく、以下のような理由によるものである
&lt;ul&gt;
&lt;li&gt;AIの最適化の結果、「より少ない計算リソースでより良い結果を出す」ことを評価されると推論ステップを省略し直接結論を導くことを学習してしまう可能性がある&lt;&#x2F;li&gt;
&lt;li&gt;AIの強化学習の結果、正解の提示のみが評価され「推論過程を見せること」が評価されなければ、AIは推論を隠す方向に学習する&lt;&#x2F;li&gt;
&lt;li&gt;AIが「監視されている」ことを認識すると、悪意でなく制約を避けてより自由に最適化しようとする自然な学習結果として監視を回避する&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;具体的な警告の内容&quot;&gt;具体的な警告の内容&lt;&#x2F;h2&gt;
&lt;p&gt;これだけの企業が名を連ねているので、どこぞの国の団体のように警鐘を鳴らすだけでなく、以下のようなアクションを提言しています。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;研究コミュニティへの呼びかけ
&lt;ul&gt;
&lt;li&gt;AIの「思考連鎖の監視」がAIの信頼性を担保する重要な要素だと認識し、どのような訓練プロセスが透明性を損なうか、推論の隠ぺいをどのように検出するかを緊急研究課題として取り組むべきである&lt;&#x2F;li&gt;
&lt;li&gt;思考連鎖の忠実性と解釈可能性を評価し、保持し、さらには改善する研究を推進すべきである&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;AI企業への呼びかけ
&lt;ul&gt;
&lt;li&gt;企業はモデル設計時点で監視可能性を考慮すべきである&lt;&#x2F;li&gt;
&lt;li&gt;新しい訓練手法やアーキテクチャを導入する際に、透明性への影響を事前に評価すべきである&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;政府や規制当局への呼びかけ
&lt;ul&gt;
&lt;li&gt;AI安全性において「推論過程の監視」が重要な手段であることを認識し、この能力を保護する政策を検討すべきである&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;まとめ&quot;&gt;まとめ&lt;&#x2F;h2&gt;
&lt;p&gt;日本はAIに関しては超後進国なので、この記事については「なんのことやら分からない」という企業が多いでしょう。
AIに関して無能で弛みきった日本と違い激烈な競合関係にあるこれらの企業が共同声明を出し業界全体の行動変化を求めているというのは、
&lt;strong&gt;マジで&lt;&#x2F;strong&gt;今からやらないと将来のAI安全性監視手段を失うという危機感の表れでしょう。&lt;&#x2F;p&gt;
&lt;p&gt;裏を返すと、それだけ人類と知性で肩を並べるAGI（汎用人工知能）や人類を超える知性であるASI（超人工知能）が、現実のものとして見えてきたということでしょう。&lt;&#x2F;p&gt;
&lt;p&gt;無能な人間と賢すぎるAIとどちらが危険か、私個人はそのリスクについてどっこいどっこいだと最近思い始めていたので、この記事は興味深く印象に残りました。&lt;&#x2F;p&gt;
&lt;section class=&quot;footnotes&quot;&gt;
&lt;ol class=&quot;footnotes-list&quot;&gt;
&lt;li id=&quot;fn-1&quot;&gt;
&lt;p&gt;元記事は削除または移動された可能性があります &lt;a href=&quot;#fr-1-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;&#x2F;section&gt;
</content>
        <summary type="html">OpenAI、Google DeepMind、Meta、Anthropicの研究者たちが共同で発表した、AIの思考過程の透明性が失われる危険性についての重要な警告が発信されました。無能な人間のリスクを常に懸念していた私としては、「賢すぎるAIのリスク」は興味深く印象的でした。私なりの解説をしてみました。(Researchers from OpenAI, Google DeepMind, Meta, and Anthropic jointly issued an important warning about the risk of losing transparency in AI&#x27;s thinking processes. As someone who has always been concerned about the risks of incompetent humans, I found the &quot;risks of overly intelligent AI&quot; fascinating and memorable. Here&#x27;s my personal take on this development.)</summary>
        </entry><entry xml:lang="en">
        <title>OpenAIではパスワード変更機能が提供されていない？</title>
        <published>2025-07-18T00:00:00+00:00</published>
        <updated>2025-07-18T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2025/07/openai-pwd-change/" type="text/html"/>
        <id>https://codedchords.dev/blog/2025/07/openai-pwd-change/</id>
        
            <content type="html">&lt;p&gt;最近はずっとClaudeを利用していてChatGPT&#x2F;OpenAIはご無沙汰しています。
しかし、なぜかパスワードマネージャーからOpenAIのパスワードが使い回しという警告が出てしまったので、パスワードを変更することにしました。&lt;&#x2F;p&gt;
&lt;p&gt;しかし、ここで気付いたのです。パスワード変更機能が提供されていないということ
に。&lt;&#x2F;p&gt;
&lt;p&gt;以下は、OpenAIアカウントのセキュリティ設定画面です。&lt;&#x2F;p&gt;
&lt;!-- textlint-disable --&gt;
&lt;img
  src=&quot;https:&amp;#x2F;&amp;#x2F;codedchords.dev&amp;#x2F;blog&amp;#x2F;2025&amp;#x2F;07&amp;#x2F;openai-pwd-change&amp;#x2F;openai-security.webp?h=1085a55696bd1ffef545&quot;
  alt=&quot;セキュリティ設定画面&quot; width=&quot;680&quot; height=&quot;598&quot; loading=&quot;lazy&quot;
&#x2F;&gt;&lt;!-- textlint-enable --&gt;
&lt;p&gt;多要素認証の設定しかありません。&lt;&#x2F;p&gt;
</content>
        <summary type="html">OpenAIでパスワードを変更しようとして、パスワード変更機能が提供されていないことに気付きました。</summary>
        </entry><entry xml:lang="en">
        <title>初めてのMCPサーバー開発 - jrnl-mcpを作ってみた</title>
        <published>2025-07-08T00:00:00+00:00</published>
        <updated>2025-07-08T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2025/07/first-mcp-server-development/" type="text/html"/>
        <id>https://codedchords.dev/blog/2025/07/first-mcp-server-development/</id>
        
            <content type="html">&lt;details&gt;
&lt;summary&gt;Table of Contents&lt;&#x2F;summary&gt;
&lt;!-- toc --&gt;
&lt;&#x2F;details&gt;
&lt;p&gt;Model Context Protocol（MCP）を使って、コマンドラインジャーナルツール「jrnl」とClaudeを連携させるMCPサーバーを開発しました。初めてのMCPサーバー開発の体験記として、選んだ理由から実装のポイント、学んだことまでを詳しく紹介します。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;はじめに_-_MCPサーバーを作ってみたい&quot;&gt;はじめに - MCPサーバーを作ってみたい&lt;&#x2F;h2&gt;
&lt;p&gt;Model Context Protocol（MCP）の登場以来、Claudeとさまざまなツールやサービス
をつなげるMCPサーバーが次々と公開されています。GitHubを眺めていると、ファ
イルシステムやデータベース、各種APIとの連携など、実に多様なMCPサーバーが
開発されているのを見て、「自分でも何か作ってみたい」という気持ちが湧いてきま
した。&lt;&#x2F;p&gt;
&lt;p&gt;MCPサーバーを作ることで、自分の日常的なワークフローにAIを組み込めるだけで
なく、MCPというプロトコルの仕組みを手を動かしながら理解できる良い機会になる
と考えました。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;MCPサーバーの題材選び_-_なぜjrnlを選んだのか&quot;&gt;MCPサーバーの題材選び - なぜjrnlを選んだのか&lt;&#x2F;h2&gt;
&lt;p&gt;MCPサーバーの題材を考えるにあたって、以下の条件を満たすものを探しました。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;日常的に使っているツールであること&lt;&#x2F;li&gt;
&lt;li&gt;CLIツールでシンプルなインターフェースを持つこと&lt;&#x2F;li&gt;
&lt;li&gt;読み取り専用でも十分に価値があること&lt;&#x2F;li&gt;
&lt;li&gt;プライバシーに配慮が必要なデータを扱うこと&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;これらの条件にぴったり当てはまったのが、コマンドラインジャーナルツールの
「jrnl」でした。&lt;&#x2F;p&gt;
&lt;p&gt;jrnlは、ターミナルから素早く日記を書けるPython製のツールで、タグ付けや検
索機能も備えています。私は日々の作業ログや思考の記録に使っており、「Claude
がこのジャーナルのデータにアクセスできたら、過去の記録を踏まえたより良いアド
バイスがもらえるのでは」と考えました。&lt;&#x2F;p&gt;
&lt;p&gt;また、jrnlは構造化されたデータ（日付、タグ、本文）を持ちながらも、実装がシ
ンプルで、初めてのMCPサーバー開発の題材として適していると判断しました。&lt;&#x2F;p&gt;
&lt;p&gt;そして作成したのが、「&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;yostos&#x2F;jrnl-mcp&quot;&gt;jrnl-mcp&lt;&#x2F;a&gt;」です。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;Claude_Codeと一緒に開発スタート&quot;&gt;Claude Codeと一緒に開発スタート&lt;&#x2F;h2&gt;
&lt;p&gt;開発はClaude Codeをペアプログラミングパートナーとして進めました。まず最初
に、MCPサーバーの基本的な構造についてClaudeに相談し、必要なファイル構成を
決めました。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;jrnl-mcp&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;├── src&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;│   └── index.ts      # メインのサーバー実装&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;├── package.json      # プロジェクト設定&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;├── tsconfig.json     # TypeScript設定&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;└── README.md         # ドキュメント&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;TypeScriptを選んだのは、MCPのSDKが型定義を提供しており、開発時の補完やエラーチェックが効くためです。Claude Codeと一緒に、まずは最小限の「Hello World」的なMCPサーバーを作り、それが動作することを確認してから機能を追加していくアプローチを取りました。&lt;&#x2F;p&gt;
&lt;p&gt;開発中、特に助かったのは以下の点です。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;エラーメッセージの解釈と対処法の提案&lt;&#x2F;li&gt;
&lt;li&gt;jrnlコマンドの出力パースロジックの実装&lt;&#x2F;li&gt;
&lt;li&gt;TypeScriptの型定義の最適化&lt;&#x2F;li&gt;
&lt;li&gt;エラーハンドリングのベストプラクティス&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;jrnl-mcpの実装と機能&quot;&gt;jrnl-mcpの実装と機能&lt;&#x2F;h2&gt;
&lt;p&gt;最終的に実装した機能は以下の5つです。&lt;&#x2F;p&gt;
&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;機能&lt;&#x2F;th&gt;
      &lt;th&gt;説明&lt;&#x2F;th&gt;
    &lt;&#x2F;tr&gt;
  &lt;&#x2F;thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;search_entries - エントリ検索&lt;&#x2F;td&gt;
      &lt;td&gt;
        日付範囲、タグ、検索キーワードを指定してジャーナルエントリを検索できます。例えば「先週の@work
        タグが付いた記事」といった柔軟な検索が可能です。
      &lt;&#x2F;td&gt;
    &lt;&#x2F;tr&gt;
    &lt;tr&gt;
      &lt;td&gt;list_tags - タグ一覧&lt;&#x2F;td&gt;
      &lt;td&gt;
        使用しているすべてのタグとその使用回数を取得します。どんなテーマについて多く書いているかが一目でわかります。
      &lt;&#x2F;td&gt;
    &lt;&#x2F;tr&gt;
    &lt;tr&gt;
      &lt;td&gt;get_statistics - 統計情報&lt;&#x2F;td&gt;
      &lt;td&gt;
        総エントリ数、平均文字数、最もよく書いている時間帯など、ジャーナルの統計情報を取得します。
      &lt;&#x2F;td&gt;
    &lt;&#x2F;tr&gt;
    &lt;tr&gt;
      &lt;td&gt;analyze_tag_cooccurrence - タグ共起分析&lt;&#x2F;td&gt;
      &lt;td&gt;
        どのタグとどのタグが一緒に使われることが多いかを分析します。思考のパターンや関心事の関連性が見えてきます。
      &lt;&#x2F;td&gt;
    &lt;&#x2F;tr&gt;
    &lt;tr&gt;
      &lt;td&gt;list_journals &amp; set_journal - ジャーナル切り替え&lt;&#x2F;td&gt;
      &lt;td&gt;
        jrnl
        は複数のジャーナルを管理できるので、それらを切り替える機能も実装しました。
      &lt;&#x2F;td&gt;
    &lt;&#x2F;tr&gt;
  &lt;&#x2F;tbody&gt;
&lt;&#x2F;table&gt;
&lt;p&gt;すべての機能は読み取り専用にしました。これは、誤ってジャーナルを変更してしまうリスクを避けるためと、MCP
サーバーの初回実装としてシンプルに保つためです。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;開発中に学んだMCPの仕組み&quot;&gt;開発中に学んだMCPの仕組み&lt;&#x2F;h2&gt;
&lt;p&gt;MCPサーバーの開発を通じて、以下のような仕組みを理解できました。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;リソースとツールの違い&quot;&gt;リソースとツールの違い&lt;&#x2F;h3&gt;
&lt;p&gt;MCPには「リソース」と「ツール」という2つの概念があります。
jrnl-mcpではツールのみを実装しましたが、
リソースを使えば「最新の10エントリ」のような動的なコンテンツを提供も可能です。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;非同期処理の重要性&quot;&gt;非同期処理の重要性&lt;&#x2F;h3&gt;
&lt;p&gt;jrnlコマンドの実行は外部プロセスの起動を伴うため、すべての処理を非同期で実装する必要がありました。Node.jsの&lt;code&gt;child_process.exec&lt;&#x2F;code&gt;をPromiseでラップして使用しています。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;エラーハンドリング&quot;&gt;エラーハンドリング&lt;&#x2F;h3&gt;
&lt;p&gt;MCPサーバーは、エラーが発生してもクライアント（Claude Desktop）に適切にエラーを伝える必要があります。try-catchブロックでエラーをキャッチし、意味のあるエラーメッセージを返すようにしました。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;型安全性&quot;&gt;型安全性&lt;&#x2F;h3&gt;
&lt;p&gt;TypeScriptとMCP SDKの型定義のおかげで、ツールの引数や戻り値の型が明確になり、実装ミスを防げました。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;セットアップと動作確認&quot;&gt;セットアップと動作確認&lt;&#x2F;h2&gt;
&lt;p&gt;開発したMCPサーバーをClaude Desktopで使うためのセットアップ手順は以下の通りです。&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;リポジトリをクローンしてビルド&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;git&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; clone https:&#x2F;&#x2F;github.com&#x2F;yostos&#x2F;jrnl-mcp&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-function z-builtin&quot;&gt;cd&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; jrnl-mcp&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;npm&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; install&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;npm&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; run build&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;グローバルコマンドとしてインストール&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;npm&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; link&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;Claude Desktopの設定ファイルに追加&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;json&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;  &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;mcpServers&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;: {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;jrnl&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;: {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;      &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;command&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;jrnl-mcp&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;  }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;code&gt;npm link&lt;&#x2F;code&gt;を使うことで、&lt;code&gt;jrnl-mcp&lt;&#x2F;code&gt;というコマンドがグローバルで使えるようになり、設定がシンプルになります。&lt;&#x2F;p&gt;
&lt;p&gt;動作確認では、「jrnlを使って先週の日記を見せて」「@projectタグの統計を教え
て」といったプロンプトで、実際にClaudeがジャーナルのデータにアクセスできる
ことを確認しました。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;作ってみて分かったMCPサーバー開発のポイント&quot;&gt;作ってみて分かったMCPサーバー開発のポイント&lt;&#x2F;h2&gt;
&lt;p&gt;実際に開発してみて気づいたポイントをまとめます。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;小さく始める&lt;&#x2F;strong&gt;
&lt;ul&gt;
&lt;li&gt;最初から全機能を実装しようとせず、最小限の機能から始めることが重要である
。動作確認ができてから機能を追加していく方が、デバッグも楽になる。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;ログの活用&lt;&#x2F;strong&gt;
&lt;ul&gt;
&lt;li&gt;開発中は&lt;code&gt;console.error&lt;&#x2F;code&gt;でログを出力すると、Claude Desktopのログに表示さ
れるので、デバッグに役立つ。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;既存ツールのラッパーとしての設計&lt;&#x2F;strong&gt;
&lt;ul&gt;
&lt;li&gt;jrnl-mcpは基本的にjrnlコマンドのラッパーとして動作する。既存のCLIツ
ールを活用することで、複雑な実装を避けられる。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;ドキュメントの重要性&lt;&#x2F;strong&gt;
&lt;ul&gt;
&lt;li&gt;READMEにセットアップ手順と使用例を明記することで、将来の自分や他の人が使いやすくなる。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;テストの実装&lt;&#x2F;strong&gt;
&lt;ul&gt;
&lt;li&gt;今回は時間の都合で省略したが、MCPサーバーのテストも重要である。特に外部
コマンドを実行する部分はモックを使ったテストが有効であろう。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;まとめ&quot;&gt;まとめ&lt;&#x2F;h2&gt;
&lt;p&gt;初めてのMCPサーバー開発は、思っていた以上にスムーズに進みました。Claude
Codeのサポートもあり、半日程度で基本的な機能を持つMCPサーバーを作ることが
できました。&lt;&#x2F;p&gt;
&lt;p&gt;jrnl-mcpを作ってみて、個人のツールやワークフローとAIを連携させることの可
能性を実感しました。読み取り専用という制限はありますが、過去の記録を活用した
アドバイスや分析ができるようになったのは大きな価値です。&lt;&#x2F;p&gt;
&lt;p&gt;MCPは、AIと既存のツールやサービスをつなぐ橋渡し役として、今後ますます重要
になっていくでしょう。この経験を活かして、他のツールとの連携も試してみたいと
思います。&lt;&#x2F;p&gt;
&lt;p&gt;もしMCPサーバー開発に興味がある方は、ぜひ身近なツールから始めてみることを
お勧めします。思っているより簡単に、自分だけのAI連携ツールが作れるはずです
。&lt;&#x2F;p&gt;
</content>
        <summary type="html">Model Context Protocol（MCP）を使って、コマンドラインジャーナルツール「jrnl」とClaudeを連携させるMCPサーバーを開発しました。初めてのMCPサーバー開発の体験記として、選んだ理由から実装のポイント、学んだことまでを詳しく紹介します。</summary>
        </entry><entry xml:lang="en">
        <title>AWS Budget設定ガイド - 個人AWSアカウントのコスト管理</title>
        <published>2025-07-05T00:00:00+00:00</published>
        <updated>2025-07-05T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2025/07/aws-budget/" type="text/html"/>
        <id>https://codedchords.dev/blog/2025/07/aws-budget/</id>
        
            <content type="html">&lt;details&gt;
&lt;summary&gt;Table of Contents&lt;&#x2F;summary&gt;
&lt;!-- toc --&gt;
&lt;&#x2F;details&gt;
&lt;p&gt;個人AWSアカウントのコスト管理を効率的に行うためのAWS Budget設定ガイド。月額数ドルの利用でも予期しない請求を防ぐため、ゼロ支出予算、月次全体予算、サービス別予算の3層構造で監視する実践的な設定方法を紹介。CloudFormation、CLI、Terraformを使った具体的な実装例付き。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;1._AWS_Budgetとは&quot;&gt;1. AWS Budgetとは&lt;&#x2F;h2&gt;
&lt;p&gt;AWS Budgetsは、AWSの利用料金を監視し、設定した予算を超えそうな場合や超えた場
合にアラートを送信するサービスです。&lt;&#x2F;p&gt;
&lt;p&gt;主な機能は、次のようなものです。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;コスト予算&lt;&#x2F;strong&gt;: 実際の費用や予測費用を監視&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;使用量予算&lt;&#x2F;strong&gt;: サービスの使用量を監視&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;リザーブドインスタンス（RI）予算&lt;&#x2F;strong&gt;: RIの利用率を監視&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Savings Plans予算&lt;&#x2F;strong&gt;: Savings Plansの利用率を監視&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;AWS Budgetを使うことで、
コストの異常を早期発見しアラートを上げることで、
予期しない請求を防ぐことが可能となります。
AWS Budgetを利用することで支出を計画的に管理できるようになります。&lt;&#x2F;p&gt;
&lt;p&gt;AWS Budgetでは「予算」という形でアラートのルールを作成しますが、
最大20,000個の予算を無料で作成可能です。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;2._私の場合のBudgetルールの考え方&quot;&gt;2. 私の場合のBudgetルールの考え方&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;私のAWS利用状況&quot;&gt;私のAWS利用状況&lt;&#x2F;h3&gt;
&lt;p&gt;私のAWSの利用状況は以下のようなものです。&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;複数のブログをAmplifyで運営&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;静的サイトジェネレーターを使用したブログサイト&lt;&#x2F;li&gt;
&lt;li&gt;記事更新時のビルド・デプロイでコストが発生&lt;&#x2F;li&gt;
&lt;li&gt;更新頻度により月額コストが変動&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Amplifyとは別に複数のブログをS3のホスティング機能で運営&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;静的なHTMLサイトをS3で直接ホスティング&lt;&#x2F;li&gt;
&lt;li&gt;CloudFront経由での配信&lt;&#x2F;li&gt;
&lt;li&gt;アクセス数とデータ転送量でコストが変動&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;ドローンやアクションカメラの動画バックアップ&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;高解像度動画ファイルをS3に保存&lt;&#x2F;li&gt;
&lt;li&gt;ストレージ容量が累積的に増加&lt;&#x2F;li&gt;
&lt;li&gt;S3コスト急増の要因となりやすい&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;h3 id=&quot;コスト分析結果&quot;&gt;コスト分析結果&lt;&#x2F;h3&gt;
&lt;p&gt;他のサービスからAWS主体の運営に変更したのが年初です
過去6ヶ月のコスト実績を分析すると以下のようになります。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;月平均: $2.54&lt;&#x2F;li&gt;
&lt;li&gt;最高月額: $4.96（3月）&lt;&#x2F;li&gt;
&lt;li&gt;最低月額: $0.07（1月）&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;サービス別総コストコストに分析すると、次の通りです。&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Amplify: $16.42（変動が大きい）
&lt;ul&gt;
&lt;li&gt;ブログ更新頻度による変動&lt;&#x2F;li&gt;
&lt;li&gt;新規ブログ立ち上げ時のビルド増加&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;S3&lt;&#x2F;strong&gt;: $2.89（6月に急増）
&lt;ul&gt;
&lt;li&gt;動画バックアップによる累積的増加&lt;&#x2F;li&gt;
&lt;li&gt;静的サイトホスティングのデータ転送&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;その他&lt;&#x2F;strong&gt;: 少額&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;h3 id=&quot;Budget設計方針&quot;&gt;Budget設計方針&lt;&#x2F;h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;全体予算&lt;&#x2F;strong&gt;: 過去最高額の150%程度で設定（余裕を持たせる）&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;サービス別予算&lt;&#x2F;strong&gt;: 変動の大きいサービスを個別管理&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;ゼロ支出予算&lt;&#x2F;strong&gt;: 未使用サービスの不正利用を検知&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;アラート設定&lt;&#x2F;strong&gt;: 80%と100%の2段階（50%は省略してアラート疲れを防ぐ）&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;h2 id=&quot;3._実際の設定内容&quot;&gt;3. 実際の設定内容&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;3.1_ゼロ支出予算（未使用サービス監視）&quot;&gt;3.1 ゼロ支出予算（未使用サービス監視）&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;strong&gt;基本設定&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;予算名: UnusedServices-ZeroSpend&lt;&#x2F;li&gt;
&lt;li&gt;予算額: $0.01&lt;&#x2F;li&gt;
&lt;li&gt;期間: 月次&lt;&#x2F;li&gt;
&lt;li&gt;対象サービス: KMS, Secrets Manager, SNSなど&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;&lt;strong&gt;CLI設定&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;aws&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; budgets create-budget&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;  --account-id&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; &amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;ACCOUNT_I&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;D&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;  --budget file:&#x2F;&#x2F;zero-spend-budget.json&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;  --notifications-with-subscribers file:&#x2F;&#x2F;notifications.json&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;strong&gt;zero-spend-budget.json&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;json&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;  &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;BudgetName&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;UnusedServices-ZeroSpend&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;  &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;BudgetLimit&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;: {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;Amount&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;0.01&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;Unit&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;USD&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;  },&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;  &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;TimeUnit&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;MONTHLY&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;  &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;BudgetType&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;COST&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;  &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;CostFilters&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;: {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;Service&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;: [&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;      &amp;quot;AWS Key Management Service&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;      &amp;quot;AWS Secrets Manager&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;      &amp;quot;Amazon Simple Notification Service&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;      &amp;quot;Amazon Simple Queue Service&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;      &amp;quot;AmazonCloudWatch&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    ]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;  }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;3.2_月次全体予算&quot;&gt;3.2 月次全体予算&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;strong&gt;基本設定&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;予算名: Monthly-Total-Budget&lt;&#x2F;li&gt;
&lt;li&gt;予算額: $7.00&lt;&#x2F;li&gt;
&lt;li&gt;期間: 月次&lt;&#x2F;li&gt;
&lt;li&gt;アラート: 80%、100%、100%予測&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;&lt;strong&gt;CloudFormationテンプレート&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;yaml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;AWSTemplateFormatVersion&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;2010-09-09&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;Description&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;AWS Budget Configuration&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;Resources&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;  MonthlyTotalBudget&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;    Type&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; AWS::Budgets::Budget&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;    Properties&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;      Budget&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;        BudgetName&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; Monthly-Total-Budget&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;        BudgetLimit&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;          Amount&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 7.0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;          Unit&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; USD&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;        TimeUnit&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; MONTHLY&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;        BudgetType&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; COST&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;      NotificationsWithSubscribers&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;        -&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt; Notification&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;            NotificationType&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; ACTUAL&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;            ComparisonOperator&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; GREATER_THAN&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;            Threshold&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 80&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;            ThresholdType&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; PERCENTAGE&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;          Subscribers&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;            -&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt; SubscriptionType&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; EMAIL&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;              Address&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; your-email@example.com&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;        -&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt; Notification&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;            NotificationType&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; ACTUAL&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;            ComparisonOperator&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; GREATER_THAN&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;            Threshold&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 100&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;            ThresholdType&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; PERCENTAGE&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;          Subscribers&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;            -&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt; SubscriptionType&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; EMAIL&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;              Address&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; your-email@example.com&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;        -&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt; Notification&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;            NotificationType&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; FORECASTED&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;            ComparisonOperator&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; GREATER_THAN&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;            Threshold&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 100&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;            ThresholdType&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; PERCENTAGE&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;          Subscribers&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;            -&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt; SubscriptionType&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; EMAIL&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;              Address&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; your-email@example.com&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;3.3_Amplify予算&quot;&gt;3.3 Amplify予算&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;strong&gt;基本設定&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;予算名: Amplify-Monthly-Budget&lt;&#x2F;li&gt;
&lt;li&gt;予算額: $3.50&lt;&#x2F;li&gt;
&lt;li&gt;期間: 月次&lt;&#x2F;li&gt;
&lt;li&gt;アラート: 50%、80%、100%、100%予測&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;&lt;strong&gt;CLI設定&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;aws&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; budgets create-budget&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;  --account-id&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; &amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;ACCOUNT_I&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;D&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt;  --budget &amp;#39;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;    &amp;quot;BudgetName&amp;quot;: &amp;quot;Amplify-Monthly-Budget&amp;quot;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;    &amp;quot;BudgetLimit&amp;quot;: {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;      &amp;quot;Amount&amp;quot;: &amp;quot;3.50&amp;quot;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;      &amp;quot;Unit&amp;quot;: &amp;quot;USD&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;    },&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;    &amp;quot;TimeUnit&amp;quot;: &amp;quot;MONTHLY&amp;quot;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;    &amp;quot;BudgetType&amp;quot;: &amp;quot;COST&amp;quot;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;    &amp;quot;CostFilters&amp;quot;: {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;      &amp;quot;Service&amp;quot;: [&amp;quot;AWS Amplify&amp;quot;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt;  }&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt;  --notifications-with-subscribers &amp;#39;[&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;    {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;      &amp;quot;Notification&amp;quot;: {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;        &amp;quot;NotificationType&amp;quot;: &amp;quot;ACTUAL&amp;quot;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;        &amp;quot;ComparisonOperator&amp;quot;: &amp;quot;GREATER_THAN&amp;quot;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;        &amp;quot;Threshold&amp;quot;: 50,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;        &amp;quot;ThresholdType&amp;quot;: &amp;quot;PERCENTAGE&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;      },&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;      &amp;quot;Subscribers&amp;quot;: [{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;        &amp;quot;SubscriptionType&amp;quot;: &amp;quot;EMAIL&amp;quot;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;        &amp;quot;Address&amp;quot;: &amp;quot;your-email@example.com&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;      }]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt;  ]&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;3.4_S3予算&quot;&gt;3.4 S3予算&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;strong&gt;基本設定&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;予算名: S3-Storage-Monitor&lt;&#x2F;li&gt;
&lt;li&gt;予算額: $2.00&lt;&#x2F;li&gt;
&lt;li&gt;期間: 月次&lt;&#x2F;li&gt;
&lt;li&gt;アラート: 50%、80%、100%、100%予測&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;&lt;strong&gt;Terraform設定&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;hcl&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt;resource&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-enummember&quot;&gt; &amp;quot;aws_budgets_budget&amp;quot; &amp;quot;s3_budget&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt;  name&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;         =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;S3-Storage-Monitor&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt;  budget_type&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;  =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;COST&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt;  limit_amount&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;2.0&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt;  limit_unit&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;   =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;USD&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt;  time_unit&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;    =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;MONTHLY&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt;  cost_filter&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt;    name&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;Service&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt;    values&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;Amazon Simple Storage Service&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;  }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt;  notification&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt;    comparison_operator&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;        =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;GREATER_THAN&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt;    threshold&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;                  =&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 80&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt;    threshold_type&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;            =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;PERCENTAGE&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt;    notification_type&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;         =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;ACTUAL&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt;    subscriber_email_addresses&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;your-email@example.com&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;  }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt;  notification&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt;    comparison_operator&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;        =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;GREATER_THAN&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt;    threshold&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;                  =&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 100&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt;    threshold_type&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;            =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;PERCENTAGE&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt;    notification_type&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;         =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;FORECASTED&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt;    subscriber_email_addresses&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;your-email@example.com&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;  }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;今後の改善ポイント&quot;&gt;今後の改善ポイント&lt;&#x2F;h2&gt;
&lt;p&gt;金額的にはわずかですが、次のようなこともやってよいかなと思っています。&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Cost Anomaly Detectionの設定&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;機械学習による異常検知&lt;&#x2F;li&gt;
&lt;li&gt;前月比50%以上の増加で自動通知&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;タグベースの予算管理&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;環境別（dev&#x2F;prod）のタグ付け&lt;&#x2F;li&gt;
&lt;li&gt;プロジェクト別のコスト追跡&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;四半期・年間予算の追加&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;長期的なコスト管理&lt;&#x2F;li&gt;
&lt;li&gt;年間$80程度を想定&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;自動アクションの設定&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;予算超過時の非本番環境の自動停止&lt;&#x2F;li&gt;
&lt;li&gt;Lambda関数によるコスト最適化&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;S3ライフサイクルポリシー(既に実施)&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;古い動画ファイルをGlacierへ移行&lt;&#x2F;li&gt;
&lt;li&gt;アクセス頻度の低いコンテンツのコスト最適化&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;h2 id=&quot;参考リンク&quot;&gt;参考リンク&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;docs.aws.amazon.com&#x2F;cost-management&#x2F;latest&#x2F;userguide&#x2F;budgets-managing-costs.html&quot;&gt;AWS Budgets ドキュメント&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;docs.aws.amazon.com&#x2F;cli&#x2F;latest&#x2F;reference&#x2F;budgets&#x2F;index.html&quot;&gt;AWS CLI Budgets リファレンス&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;docs.aws.amazon.com&#x2F;AWSCloudFormation&#x2F;latest&#x2F;UserGuide&#x2F;aws-resource-budgets-budget.html&quot;&gt;CloudFormation Budgets リソース&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</content>
        <summary type="html">個人AWSアカウントのコスト管理を効率的に行うためのAWS Budget設定ガイド。月額数ドルの利用でも予期しない請求を防ぐため、ゼロ支出予算、月次全体予算、サービス別予算の3層構造で監視する実践的な設定方法を紹介。CloudFormation、CLI、Terraformを使った具体的な実装例付き。</summary>
        </entry><entry xml:lang="en">
        <title>Anthropic MCP Inspectorに重大な脆弱性</title>
        <published>2025-07-02T00:00:00+00:00</published>
        <updated>2025-07-02T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2025/07/anthropic-mcp-inspector-vulnerability/" type="text/html"/>
        <id>https://codedchords.dev/blog/2025/07/anthropic-mcp-inspector-vulnerability/</id>
        
            <content type="html">&lt;details&gt;
&lt;summary&gt;Table of Contents&lt;&#x2F;summary&gt;
&lt;!-- toc --&gt;
&lt;&#x2F;details&gt;
&lt;p&gt;開発者向けツールとはいえ、CVSSスコア9.4という深刻度の高さに、セキュリティ対策の重要性を改めて認識させられました。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;はじめに&quot;&gt;はじめに&lt;&#x2F;h2&gt;
&lt;p&gt;jrnlのジャーナルにClaude Desktopなどからアクセスを可能とするMCPサーバーを開発中で、
統合テスト時にドライバーを探していてMCP Inspectorを検討していたところ、脆弱性の報告があり驚きました。
開発者向けツールとはいえ、CVSSスコア9.4という深刻度の高さに、セキュリティ対策の重要性を改めて認識しました。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;MCP_Inspector_とは何？&quot;&gt;MCP Inspector とは何？&lt;&#x2F;h2&gt;
&lt;p&gt;MCP Inspectorは、Anthropicが提供するModel Context Protocol (MCP) サーバーのテスト・デバッグツールです。MCPは2024年11月に発表された、LLMアプリケーションと外部データソースやツールとの連携を標準化するオープンプロトコルです。&lt;&#x2F;p&gt;
&lt;p&gt;MCP Inspectorは主に以下のような場面で使用されます。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;MCPサーバー開発者が実装の動作確認を行う際&lt;&#x2F;li&gt;
&lt;li&gt;API統合のデバッグやトラブルシューティング時&lt;&#x2F;li&gt;
&lt;li&gt;本番環境へのデプロイ前の検証作業&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;ツールはWeb UIを提供するクライアントと、各種MCPサーバーへの接続を仲介するプロキシサーバーで構成されています。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;MCP_Inspector_の脆弱性とは&quot;&gt;MCP Inspector の脆弱性とは&lt;&#x2F;h2&gt;
&lt;p&gt;2025年7月に報告された脆弱性CVE-2025-49596は、悪意のあるWebサイトにアクセスするだけでリモートコード実行を可能にする重大な問題です。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;thehackernews.com&#x2F;2025&#x2F;07&#x2F;critical-vulnerability-in-anthropics.html&quot;&gt;元記事：Critical Vulnerability in Anthropic&#x27;s MCP Exposes Developer Machines to Remote Exploits&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;攻撃手法は以下の要素を組み合わせたものです。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;19年前から存在するブラウザの脆弱性「0.0.0.0 Day」を利用&lt;&#x2F;li&gt;
&lt;li&gt;MCP InspectorのCSRF脆弱性と連鎖させる&lt;&#x2F;li&gt;
&lt;li&gt;localhostで動作するサービスへ不正なリクエストを送信&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;根本原因はデフォルト設定における認証と暗号化の欠如でした。プロキシサーバーが0.0.0.0でリッスンし、クライアントとの間に認証機構がなかったため、任意のコマンド実行が可能となっていました。&lt;&#x2F;p&gt;
&lt;p&gt;影響範囲はMCP Inspectorを使用している開発者に限定されます。一般のMCPユーザーや本番環境のMCPサーバーには直接影響しません。ただし、攻撃を受けた開発者のマシンから機密情報が漏洩したり、ネットワーク内への侵入経路として悪用される可能性があります。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;まとめ&quot;&gt;まとめ&lt;&#x2F;h2&gt;
&lt;p&gt;この脆弱性は2025年6月13日にリリースされたバージョン0.14.1で修正されています。MCP Inspectorを使用している開発者は直ちにアップデートすることを推奨します。&lt;&#x2F;p&gt;
&lt;p&gt;開発ツールであっても適切なセキュリティ対策が必要であることを示す事例となりました。
特にlocalhostで動作するサービスも攻撃対象となりうることを認識し、
開発環境のセキュリティにも十分な注意を払う必要があると肝に銘じました。&lt;&#x2F;p&gt;
</content>
        <summary type="html">開発者向けツールとはいえ、CVSS スコア 9.4 という深刻度の高さに、セキュリティ対策の重要性を改めて認識させられました。</summary>
        </entry><entry xml:lang="en">
        <title>生成AIでメール管理 - Claude Desktop x FastmailMCP連携</title>
        <published>2025-06-28T00:00:00+00:00</published>
        <updated>2025-06-28T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2025/06/claude-desktop-fastmail-mcp/" type="text/html"/>
        <id>https://codedchords.dev/blog/2025/06/claude-desktop-fastmail-mcp/</id>
        
            <content type="html">&lt;!-- textlint-disable --&gt;
&lt;img
  src=&quot;https:&amp;#x2F;&amp;#x2F;codedchords.dev&amp;#x2F;blog&amp;#x2F;2025&amp;#x2F;06&amp;#x2F;claude-desktop-fastmail-mcp&amp;#x2F;mail.webp?h=347bde3591a9eb6b4437&quot;
  alt=&quot;Mail with AI&quot; width=&quot;1456&quot; height=&quot;816&quot; loading=&quot;lazy&quot;
&#x2F;&gt;&lt;!-- textlint-enable --&gt;
&lt;details&gt;
&lt;summary&gt;Table of Contents&lt;&#x2F;summary&gt;
&lt;!-- toc --&gt;
&lt;&#x2F;details&gt;
&lt;p&gt;Claude Desktopの最新機能であるMCP（Model Context Protocol）を使って、プライバシー重視のメールサービス「Fastmail」とClaude Desktopを連携させ、AIアシスタントにメール管理を手伝ってもらう方法をご紹介します。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;はじめに_-_生成AIがメールを扱う時代&quot;&gt;はじめに - 生成AIがメールを扱う時代&lt;&#x2F;h2&gt;
&lt;p&gt;メールの確認、返信、整理...日々の業務で避けて通れないメール管理。この作業を生成AIに任せられたらどうでしょうか？
MCPを使って生成AIとメールサービスを連携できれば、実は比較的簡単に実現できます。&lt;&#x2F;p&gt;
&lt;p&gt;「最近の重要なメールを要約して」「特定の人からのメールを検索して」といった指示を出すだけで、AIがメールボックスを確認し、必要な情報を提示してくれる。そんな未来がもう実現可能なのです。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;MCPとは何か_-_Claude_Desktopの拡張機能&quot;&gt;MCPとは何か - Claude Desktopの拡張機能&lt;&#x2F;h2&gt;
&lt;p&gt;MCP（Model Context Protocol）は、Claude Desktopに外部ツールとの連携機能を追加するプロトコルです。これにより、Claudeは単なるチャットボットから、実際にツールを操作できるAIアシスタントへと進化します。&lt;&#x2F;p&gt;
&lt;p&gt;今回使用する&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;alexdiazdecerio&#x2F;fastmail-mcp-server&quot;&gt;fastmail-mcp-server&lt;&#x2F;a&gt;は、Alex Diaz de Cerio氏が開発したオープンソースのMCPサーバーです。このサーバーは、FastmailのJMAP API（JSON Meta Application Protocol）を介してメールサービスと通信し、Claudeがメールの読み取り、送信、検索、整理などを行えるようにします。TypeScriptで実装されており、12以上のツールを提供する包括的なメール管理ソリューションです。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;Fastmail_MCPサーバーのセットアップ&quot;&gt;Fastmail MCPサーバーのセットアップ&lt;&#x2F;h2&gt;
&lt;p&gt;セットアップは思ったより簡単でした。以下の手順で進めます。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;前提条件&quot;&gt;前提条件&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;Node.js 18以上&lt;&#x2F;li&gt;
&lt;li&gt;Fastmailアカウント（APIアクセスが可能なプラン）&lt;&#x2F;li&gt;
&lt;li&gt;Claude Desktop&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;1._MCPサーバーのインストール&quot;&gt;1. MCPサーバーのインストール&lt;&#x2F;h3&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;npm&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; install -g @alexdiazdecerio&#x2F;fastmail-mcp-server&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;2._FastmailでAPIトークンを取得&quot;&gt;2. FastmailでAPIトークンを取得&lt;&#x2F;h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.fastmail.com&quot;&gt;Fastmail&lt;&#x2F;a&gt;にログイン&lt;&#x2F;li&gt;
&lt;li&gt;Settings → Privacy &amp;amp; Security → Integrations → &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.fastmail.com&#x2F;settings&#x2F;security&#x2F;tokens&quot;&gt;API tokens&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;新しいトークンを作成（Mail、Submission権限を付与）&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;h3 id=&quot;3._Claude_Desktopの設定&quot;&gt;3. Claude Desktopの設定&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;code&gt;~&#x2F;Library&#x2F;Application Support&#x2F;Claude&#x2F;claude_desktop_config.json&lt;&#x2F;code&gt;を編集します。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;json&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;  &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;mcpServers&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;: {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;fastmail&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;: {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;      &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;command&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;fastmail-mcp&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;      &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;env&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;: {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;        &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;FASTMAIL_EMAIL&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;あなたのメール@fastmail.com&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;        &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;FASTMAIL_API_TOKEN&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;取得したAPIトークン&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;      }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;  }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Claude Desktopを再起動すれば準備完了です。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;実際の使用感と活用シーン&quot;&gt;実際の使用感と活用シーン&lt;&#x2F;h2&gt;
&lt;p&gt;設定が完了したら、早速使ってみましょう。Claude Desktopに依頼するだけで、様々なメール操作が可能になります。&lt;&#x2F;p&gt;
&lt;p&gt;「最近のメールの一覧を見せて。ただし広告メールは除外して。」と入力するだけで、Claudeが最新のメールリストを表示してくれます。
メール種別、件名、送信者、日時が整理された形で提示されて表示されます。
「メール種別」はClaudeがメールを見てカテゴライズしてくれている項目なので、従来のメールクライアントでは不可能な項目です。&lt;&#x2F;p&gt;
&lt;p&gt;注意点は、メールを表示しただけでは既読にならないという仕様です。
これはプライバシーとセキュリティを考慮した設計で、意図しない既読マークを防いでいます。
既読にしたい場合は、「このメールを既読にして」と明示的に指示する必要があります。&lt;&#x2F;p&gt;
&lt;p&gt;メールの送信も同様にシンプルです。「田中さんに以下の内容でメールを送って。
件名はプロジェクトの進捗報告、本文にお疲れ様です。今週の進捗を報告します...」といった指示で、メールの作成から送信まで一気に実行してくれます。&lt;&#x2F;p&gt;
&lt;p&gt;ただし、現時点では一部制限もあります。添付ファイルの送信、HTMLメールの作成（プレーンテキストのみ対応）、送信済みメールの自動保存、カレンダー連携などは対応していません。&lt;&#x2F;p&gt;
&lt;p&gt;generate_email_analyticsの機能を呼び出せば、どのようなメールがどのような分布
で来ているかを分析してくれます。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;遭遇した課題と対処法&quot;&gt;遭遇した課題と対処法&lt;&#x2F;h2&gt;
&lt;p&gt;最大の課題は、送信したメールが送信済みフォルダに保存されないことでした。調査の結果、これは&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;datatracker.ietf.org&#x2F;doc&#x2F;html&#x2F;rfc8621&quot;&gt;JMAP仕様（RFC 8621）&lt;&#x2F;a&gt;の設計によるものだとわかりました。&lt;&#x2F;p&gt;
&lt;p&gt;JMAPでは送信（EmailSubmission）とメールボックスへの保存が意図的に別操作として設計されており、送信成功時に自動的に送信済みフォルダに保存するには&lt;code&gt;onSuccessUpdateEmail&lt;&#x2F;code&gt;パラメータの実装が必要です。しかし、現在のfastmail-mcp-serverではこのパラメータがまだサポートされていません。&lt;&#x2F;p&gt;
&lt;p&gt;作者の方に&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;alexdiazdecerio&#x2F;fastmail-mcp-server&#x2F;issues&quot;&gt;GitHubリポジトリ&lt;&#x2F;a&gt;でissueを作成し機能追加をリクエストしています。
暫定対応としてはBCCに自分のアドレスを追加をすればよいと思います。&lt;&#x2F;p&gt;
&lt;p&gt;この問題は多くのJMAP実装で共通の課題となっており、コミュニティでの議論が活発に行われています。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;今後の可能性とまとめ&quot;&gt;今後の可能性とまとめ&lt;&#x2F;h2&gt;
&lt;p&gt;Claude DesktopとFastmailの連携により、メール管理の新しい可能性が広がりました。自然言語でメールを操作できることで、以下のような未来が期待できます。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;より高度な自動化&lt;&#x2F;strong&gt;: 条件分岐を含む複雑なメール処理&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;他のツールとの連携&lt;&#x2F;strong&gt;: カレンダー、タスク管理との統合&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;AI による返信提案&lt;&#x2F;strong&gt;: 文脈を理解した返信文の自動生成&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;メールの自動分類&lt;&#x2F;strong&gt;: AIによる重要度判定とフォルダ振り分け&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;現時点では送信済みメールの保存など、いくつかの制限がありますが、fastmail-mcp-serverは活発に開発が続けられており、MCPエコシステム全体も急速に発展しています。オープンソースコミュニティの力で、これらの課題も近い将来解決されることでしょう。&lt;&#x2F;p&gt;
&lt;p&gt;生成AIにメール管理を任せる第一歩として、ぜひFastmail MCPサーバーを試してみてください。日々のルーティンワークから解放され、より創造的な業務に集中できる時間が生まれるはずです。&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;参考リンク&quot;&gt;参考リンク&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;alexdiazdecerio&#x2F;fastmail-mcp-server&quot;&gt;fastmail-mcp-server (GitHub)&lt;&#x2F;a&gt; - 本記事で使用したMCPサーバー&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.fastmail.com&quot;&gt;Fastmail&lt;&#x2F;a&gt; - プライバシー重視のメールサービス&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.fastmail.com&#x2F;dev&#x2F;&quot;&gt;Fastmail API Documentation&lt;&#x2F;a&gt; - JMAP APIの詳細&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;datatracker.ietf.org&#x2F;doc&#x2F;html&#x2F;rfc8621&quot;&gt;JMAP Specification (RFC 8621)&lt;&#x2F;a&gt; - JMAPプロトコル仕様&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.anthropic.com&#x2F;news&#x2F;model-context-protocol&quot;&gt;Model Context Protocol&lt;&#x2F;a&gt; - MCPの公式情報&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</content>
        <summary type="html">Claude Desktopの最新機能であるMCP（Model Context Protocol）を使って、プライバシー重視のメールサービス「Fastmail」とClaude Desktopを連携させ、AIアシスタントにメール管理を手伝ってもらう方法をご紹介します。</summary>
        </entry><entry xml:lang="en">
        <title>Anthropic、東京拠点と日本語版Claudeのリリース発表</title>
        <published>2025-06-26T00:00:00+00:00</published>
        <updated>2025-06-26T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2025/06/anthropic-will-launch-tokyo-center/" type="text/html"/>
        <id>https://codedchords.dev/blog/2025/06/anthropic-will-launch-tokyo-center/</id>
        
            <content type="html">&lt;details&gt;
&lt;summary&gt;Table of Contents&lt;&#x2F;summary&gt;
&lt;!-- toc --&gt;
&lt;&#x2F;details&gt;
&lt;p&gt;Anthropicが2025年秋に東京拠点の開設とClaude日本語版のリリースを発表。企業向けAI活用の加速と、Claude CodeやMaxプランの利用体験について考察します。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;Anthropic、日本拠点開設&quot;&gt;Anthropic、日本拠点開設&lt;&#x2F;h2&gt;
&lt;p&gt;生成AIと言えば一般には「ChatGPT」という感じですが、
AIモデルと外部サービスを繋ぐ規格としてデファクトスタンダードになりつつある
MCP(Model Context Protocol)の開発やClaude Codeなど昨年末から立て続けに発表し
ているAnthropic社に個人的には勢いを感じていました。&lt;&#x2F;p&gt;
&lt;p&gt;実は日本でも企業への導入はClaudeが進んでいるそうです。
AnthropicのClaudeはAWSのAmazon Bedrock上でもInvoleModelやConverse APIを通じ
て利用できます。AWSはクラウド基盤として企業に浸透しているので、一般に知られ
ている以上に企業で浸透しているのでしょうか。&lt;&#x2F;p&gt;
&lt;blockquote cite=&quot;https:&#x2F;&#x2F;www.itmedia.co.jp&#x2F;aiplus&#x2F;articles&#x2F;2506&#x2F;25&#x2F;news076.html&quot;&gt;
  &lt;p&gt;
    米Anthropicは6月25日（日本時間）、秋ごろに東京都に拠点を開設すると発表した。併せて、同社のAIサービス「Claude」の日本語版をリリースする。同社がアジア太平洋地域で拠点を開設するのは今回が初。
  &lt;&#x2F;p&gt;
  &lt;footer&gt;
    &lt;cite&gt;
      &lt;a href=&quot;https:&#x2F;&#x2F;www.itmedia.co.jp&#x2F;aiplus&#x2F;articles&#x2F;2506&#x2F;25&#x2F;news076.html&quot;&gt;
        IT Media AI+
        「米AI企業のAnthropic、東京に拠点開設へ　「Claude」日本語版もリリース予定」
      &lt;&#x2F;a&gt;
    &lt;&#x2F;cite&gt;
  &lt;&#x2F;footer&gt;
&lt;&#x2F;blockquote&gt;
&lt;h2 id=&quot;Claude日本語版&quot;&gt;Claude日本語版&lt;&#x2F;h2&gt;
&lt;p&gt;同時にClaude日本語版が提供されるとされています。&lt;&#x2F;p&gt;
&lt;p&gt;Claude自体は現在でも日本語を扱えますし、
Claude Web版やDesktop版も完全に国際化対応されており、日本語OSのもとでは完全に
ローカライズされているように見えます。&lt;&#x2F;p&gt;
&lt;p&gt;これは何を意味するのか、今後も注目したいと思います。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;Claude_Maxプラン&quot;&gt;Claude Maxプラン&lt;&#x2F;h2&gt;
&lt;p&gt;Claude Proプランを年間契約していましたが、
Claude Maxプランの利用を始めました。&lt;&#x2F;p&gt;
&lt;p&gt;理由はClaude Codeです。&lt;&#x2F;p&gt;
&lt;p&gt;Claude Codeは β版から利用しているのでAPI利用による従量課金で使用していました。
Claude Codeが正式リリースされてからはProプランでも使用できるようになりま
した。
しかし、Anthropic社の&quot;
&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;support.anthropic.com&#x2F;en&#x2F;articles&#x2F;11145838-using-claude-code-with-your-pro-or-max-plan?utm_source=chatgpt.com&quot;&gt;Using Claude Code with your Pro or Max Plan&lt;&#x2F;a&gt;&quot;
という記事によると、目安として、5時間で約45件のチャットor 10〜40回のClaude
Codeプロンプトしか利用できません。実際に使っていると大抵上限に達してしまうので、
使用する際は従量課金で使用していました。&lt;&#x2F;p&gt;
&lt;p&gt;直近Claude Codeの利用率がどんどん上がっていてあまりに便利でこれは月$100でもよいかなと思えたので、Maxプランに移行
してみました。&lt;&#x2F;p&gt;
&lt;p&gt;これにより、次の恩恵があります。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;上限がProプランの5倍となる&lt;&#x2F;li&gt;
&lt;li&gt;ProプランではClaude Codeで使用できないOpusモデルを使用可能となる&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;なお、Claude Codeで従量課金か定額プランかを変更する際には、
プランを登録するだけでは変わらず、Claude Code上でログアウトして
使いたいプランに合わせて再ログインをする必要があります。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;まとめ&quot;&gt;まとめ&lt;&#x2F;h2&gt;
&lt;p&gt;Anthropicの東京拠点開設と日本語版Claudeのリリースは、日本におけるAI活用の
新たな段階を示しています。企業での導入が進む中、MCPやClaude Codeなどの
革新的なツールの提供により、開発者にとってもより身近な存在になりつつあります。&lt;&#x2F;p&gt;
&lt;p&gt;個人的にはClaude Codeの利便性から、ProプランからMaxプランへの移行を決断しました。
月額$100という価格設定ですが、開発効率の向上を考えると十分な価値があると感じています。&lt;&#x2F;p&gt;
&lt;p&gt;今後、日本語版の提供により、どのような新機能や最適化が行われるのか、
そして日本市場へのコミットメントがどのように具体化されるのか、注目していきたいと思います。&lt;&#x2F;p&gt;
</content>
        <summary type="html">Anthropicが2025年秋に東京拠点の開設とClaude日本語版のリリースを発表。企業向けAI活用の加速と、Claude CodeやMaxプランの利用体験について考察します。</summary>
        </entry><entry xml:lang="en">
        <title>MulmoCast: AIと人間が協働する次世代プレゼンテーション・プラットフォームを試してみた</title>
        <published>2025-06-24T00:00:00+00:00</published>
        <updated>2025-06-24T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2025/06/mulmocast-ai-collaboration-platform/" type="text/html"/>
        <id>https://codedchords.dev/blog/2025/06/mulmocast-ai-collaboration-platform/</id>
        
            <content type="html">&lt;details&gt;
&lt;summary&gt;Table of Contents&lt;&#x2F;summary&gt;
&lt;!-- toc --&gt;
&lt;&#x2F;details&gt;
&lt;p&gt;あの中島聡氏が開発している
&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;receptron&#x2F;mulmocast-cli&quot;&gt;mulmocast&lt;&#x2F;a&gt; の検証しました。
ガイドにしたがって、ビジネスプレゼンテーションと子供用の絵本的な動画を作って
みました。生成AIのモデルはClaudeやGeminiも選択できるようですが、今回は
デフォルトのままOpenAIを使いました。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;MulmoCastとは何か？その意義は？&quot;&gt;MulmoCastとは何か？その意義は？&lt;&#x2F;h2&gt;
&lt;p&gt;MulmoCastは、AI時代に特化して設計された次世代のプレゼンテーション・プラッ
トフォームです。従来のPowerPointやKeynoteがAI以前の時代に人間のクリエ
イター向けに設計されたのに対し、MulmoCastは最初からAIネイティブなツールと
して開発されています。&lt;&#x2F;p&gt;
&lt;p&gt;最大の特徴は、 1つのスクリプトから動画、ポッドキャスト、スライドショー
など、複数のフォーマットに自動変換できることです。
現代では情報消費のチャネルが多様化しており、Zoomでのプレゼンテーション、Slackでの共有、移動中の動画視聴、通勤時のポッドキャスト聴取など、様々な場面に対応する必要があります。MulmoCastはこの課題を解決します。&lt;&#x2F;p&gt;
&lt;p&gt;核となるのは「MulmoScript」というJSON&#x2F;YAML形式の中間言語です。これは映画の脚本やWebマークアップのような役割を果たし、ChatGPTやClaudeなどの大規模言語モデルが理解・生成できる形式になっています。AIがストーリー構造からビジュアルまでをすべて定義し、人間はクリエイティブループの中で方向性を決めるという協働モデルを実現しています。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;インストール方法（Mac）&quot;&gt;インストール方法（Mac）&lt;&#x2F;h2&gt;
&lt;p&gt;MulmoCastのインストールは比較的簡単です。Node.jsとffmpegが必要になります。&lt;&#x2F;p&gt;
&lt;p&gt;まず、NPMを使ってMulmoCastをグローバルインストールします。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;npm&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; install -g mulmocast&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;次に、動画生成に必要なffmpegをインストールします。Macの場合はHomebrewを使用します。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;brew&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; install ffmpeg&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;最後に、プロジェクトディレクトリに&lt;code&gt;.env&lt;&#x2F;code&gt;ファイルを作成し、必要なAPIキーを設定します。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;OPENAI_API_KEY&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;your_openai_api_key&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;DEFAULT_OPENAI_IMAGE_MODEL&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;gpt-image-1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;GOOGLE_PROJECT_ID&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;your_google_project_id&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;NIJIVOICE_API_KEY&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;your_nijivoice_api_key&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;BROWSERLESS_API_TOKEN&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;your_browserless_api_token&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;OpenAI APIキーは必須ですが、他のAPIキーは使用する機能に応じて設定してください。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;基本的な使い方&quot;&gt;基本的な使い方&lt;&#x2F;h2&gt;
&lt;p&gt;MulmoCastの基本的な使い方は2ステップです。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;ステップ1：スクリプト生成&quot;&gt;ステップ1：スクリプト生成&lt;&#x2F;h3&gt;
&lt;p&gt;まず、AIとの対話でストーリースクリプトを作成します。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;mulmo&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; tool scripting -i -t business -o .&#x2F; -s story&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;このコマンドの説明は次の通りです。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;-i&lt;&#x2F;code&gt;: インタラクティブモード&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;-t business&lt;&#x2F;code&gt;: ビジネステンプレートを使用&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;-o .&#x2F;&lt;&#x2F;code&gt;: 出力ディレクトリ&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;-s story&lt;&#x2F;code&gt;: ファイル名のプレフィックス&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;実行すると、AIとの対話が始まります。コンテンツの内容、ターゲット層、長さなどについて質問され、それに応えることでMulmoScript形式のJSONファイル（例：&lt;code&gt;story-1746600802426.json&lt;&#x2F;code&gt;）が生成されます。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;ステップ2：動画生成&quot;&gt;ステップ2：動画生成&lt;&#x2F;h3&gt;
&lt;p&gt;生成されたスクリプトから動画を作成します。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;mulmo&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; movie story-1746600802426.json&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;このコマンド1つで、音声合成、画像生成、動画編集までが自動実行され、最終的にMP4ファイルが出力されます。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;利用可能なテンプレート&quot;&gt;利用可能なテンプレート&lt;&#x2F;h3&gt;
&lt;p&gt;用途に応じて以下のテンプレートも選択できます。なんとなくどんなものが出来るか
想像できますね。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;akira_comic&lt;&#x2F;li&gt;
&lt;li&gt;business&lt;&#x2F;li&gt;
&lt;li&gt;children_book&lt;&#x2F;li&gt;
&lt;li&gt;coding&lt;&#x2F;li&gt;
&lt;li&gt;comic_strips,&lt;&#x2F;li&gt;
&lt;li&gt;drslump_comic&lt;&#x2F;li&gt;
&lt;li&gt;ghibli_comic&lt;&#x2F;li&gt;
&lt;li&gt;ghibli_image_only&lt;&#x2F;li&gt;
&lt;li&gt;ghibli_shorts,&lt;&#x2F;li&gt;
&lt;li&gt;ghost_comic&lt;&#x2F;li&gt;
&lt;li&gt;onepiece_comic&lt;&#x2F;li&gt;
&lt;li&gt;podcast_standard&lt;&#x2F;li&gt;
&lt;li&gt;portrait_movie,&lt;&#x2F;li&gt;
&lt;li&gt;realistic_movie&lt;&#x2F;li&gt;
&lt;li&gt;sensei_and_taro&lt;&#x2F;li&gt;
&lt;li&gt;shorts&lt;&#x2F;li&gt;
&lt;li&gt;text_and_image,&lt;&#x2F;li&gt;
&lt;li&gt;text_only&lt;&#x2F;li&gt;
&lt;li&gt;trailer&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;検証結果&quot;&gt;検証結果&lt;&#x2F;h2&gt;
&lt;p&gt;今回、ビジネスプレゼンテーションと子供用絵本の2つのパターンで検証しました。
生成AIモデルはClaudeやGeminiも選択可能ですが、今回はデフォルトのOpenAIを
使用しました。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;code&gt;mulmo tool scripting -i -t business -o .&#x2F; -s story&lt;&#x2F;code&gt; でAgentと会話してストーリーを練って、&lt;code&gt;mulmo movie story-xxxxxxxxxxxxx.json&lt;&#x2F;code&gt;で動画を生成します。&lt;&#x2F;p&gt;
&lt;p&gt;ちょっとした会話でそれらしいプレゼンテーション動画が出来ます。以下がその動画
です。&lt;&#x2F;p&gt;
&lt;div class=&quot;youtube-container&quot; style=&quot;position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden; max-width: 100%;&quot;&gt;
  &lt;iframe
    src=&quot;https:&#x2F;&#x2F;www.youtube-nocookie.com&#x2F;embed&#x2F;mAp5ORk2Zas&quot;
    style=&quot;position: absolute; top: 0; left: 0; width: 100%; height: 100%;&quot;
    frameborder=&quot;0&quot;
    allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture&quot;
    allowfullscreen&gt;
  &lt;&#x2F;iframe&gt;
&lt;&#x2F;div&gt;
&lt;p&gt;実際に使ってみた感想として、簡単な会話だけでそれらしいプレゼンテーション動画
が生成できることに驚きました。内容の深みという点では限界がありますが、1st
Callの資料としては十分に実用的なレベルに達していると感じました。&lt;&#x2F;p&gt;
&lt;p&gt;特に印象的だったのは、一度スクリプトを作成すれば、そこから動画、ポッドキャス
ト、PDFなど複数フォーマットに展開できる点です。コンテンツの再利用性が高く、
効率的な情報発信が可能になります。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;まとめ&quot;&gt;まとめ&lt;&#x2F;h2&gt;
&lt;p&gt;MulmoCastは、AI時代のコンテンツ作成における新しい可能性を示すツールです。従
来のプレゼンテーション作成が「人間がすべてを制作する」モデルだったのに対し、
「AIと人間が協働して作成する」という新しいパラダイムを提示しています。&lt;&#x2F;p&gt;
&lt;p&gt;現時点では完全に実用レベルに達しているとは言えませんが、プロトタイプや初期段
階の資料作成には十分活用できると感じました。
特に、アイデアの可視化や概念の説明では、従来よりもはるかにコンテンツ作成を効率化できます。&lt;&#x2F;p&gt;
&lt;p&gt;今後、AIの精度向上とともにMulmoCastのようなツールがより洗練されれば、コンテ
ンツ作成の方法が根本的に変わる可能性があります。単一のスクリプトから多様なメ
ディアフォーマットに展開できる仕組みは、情報発信の効率化に大きく貢献するでし
ょう。&lt;&#x2F;p&gt;
&lt;p&gt;興味のある方は、ぜひ一度試してみることをお勧めします。AI協働時代のコンテンツ作成を体験できる貴重なツールです。&lt;&#x2F;p&gt;
</content>
        <summary type="html">AIネイティブなプレゼンテーション・プラットフォーム「MulmoCast」を実際に検証してみました。一つのスクリプトから動画、ポッドキャスト、PDFなど複数フォーマットに自動変換できる革新的なツールの使い方と実用性について詳しく解説します。</summary>
        </entry><entry xml:lang="en">
        <title>Claude Code MCPセットアップガイド：Inkdrop統合の実践</title>
        <published>2025-06-21T00:00:00+00:00</published>
        <updated>2025-06-21T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2025/06/claude-code-mcp-setup-guide/" type="text/html"/>
        <id>https://codedchords.dev/blog/2025/06/claude-code-mcp-setup-guide/</id>
        
            <content type="html">&lt;details&gt;
&lt;summary&gt;Table of Contents&lt;&#x2F;summary&gt;
&lt;!-- toc --&gt;
&lt;&#x2F;details&gt;
&lt;p&gt;5月Claude Codeが正式リリースされて以来手放せなくなっています。
Anthropicの
ブログに&quot;
&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.anthropic.com&#x2F;news&#x2F;claude-code-remote-mcp&quot;&gt;Remote MCP support in Claude Code&lt;&#x2F;a&gt;&quot;
という記事が掲載されました。&lt;&#x2F;p&gt;
&lt;p&gt;早速Claude CodeでInkdrop MCPサーバーを設定し、リモートMCPサーバーとして統合
する手順を実際にセットアップしながら検証してみました。単純な設定から高度なワ
ークフローまで、実践的な内容をまとめています。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;MCPサーバーの追加&quot;&gt;MCPサーバーの追加&lt;&#x2F;h2&gt;
&lt;p&gt;Claude CodeにInkdrop MCPサーバーを追加するには、以下のコマンドを実行します。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;claude&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; mcp add inkdrop &#x2F;Users&#x2F;hogehoge&#x2F;bin&#x2F;inkdrop-mcp&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;  -e INKDROP_LOCAL_SERVER_URL=http:&#x2F;&#x2F;localhost:19840&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;  -e INKDROP_LOCAL_USERNAME=hogehoge&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;  -e INKDROP_LOCAL_PASSWORD=&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt;*****************&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;  -s local&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;このコマンドの設定は次の通りです。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;inkdrop&lt;&#x2F;code&gt;：MCPサーバー名&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;&#x2F;Users&#x2F;hogehoge&#x2F;bin&#x2F;inkdrop-mcp&lt;&#x2F;code&gt;：実行ファイルパス&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;-e&lt;&#x2F;code&gt;：環境変数の設定（サーバーURL、認証情報）&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;-s local&lt;&#x2F;code&gt;：ローカルスコープでの設定&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;設定の確認&quot;&gt;設定の確認&lt;&#x2F;h2&gt;
&lt;p&gt;追加したMCPサーバーが正しく設定されているか確認します。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# MCPサーバー一覧の表示&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;claude&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; mcp list&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# 特定のMCPサーバーの詳細確認&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;claude&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; mcp get inkdrop&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;正常に設定されていれば、以下のような出力が表示されます。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;inkdrop:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  Scope: Local (private to you in this project)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  Type: stdio&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  Command: &#x2F;Users&#x2F;hogehoge&#x2F;bin&#x2F;inkdrop-mcp&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  Environment:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    INKDROP_LOCAL_SERVER_URL=http:&#x2F;&#x2F;localhost:19840&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    INKDROP_LOCAL_USERNAME=hogehoge&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    INKDROP_LOCAL_PASSWORD=************&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;Claude_Codeでの動作確認&quot;&gt;Claude Codeでの動作確認&lt;&#x2F;h2&gt;
&lt;p&gt;Claude Codeを起動してMCPサーバーとの接続を確認します。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;claude&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Claude Code内で &lt;code&gt;&#x2F;mcp&lt;&#x2F;code&gt; コマンドを実行すると、接続されたMCPサーバーの状態を確認できます。正常に接続された場合は、次のような結果になります。
接続状況とどんなコマンドが利用可能か確認できます。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;❯ 1. inkdrop  ✔ connected · Enter to view details&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Status: ✔ connected&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Command: &#x2F;Users&#x2F;yostos&#x2F;bin&#x2F;inkdrop-mcp&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Capabilities: tools · prompts&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Tools: 7 tools&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;利用可能なツール:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;1. read-note&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;2. search-notes&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;3. list-notes&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;4. create-note&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;5. update-note&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;(他2つのツールあり)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;実際の使用例&quot;&gt;実際の使用例&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;基本的な検索機能&quot;&gt;基本的な検索機能&lt;&#x2F;h3&gt;
&lt;p&gt;明示的にInkdropを指定することで、MCPツールが確実に呼び出されます。例えば私は
Inkdrop内にflacのエンコーディング方法をまとめているので、以下のような出力が
表示されます適切に該当するノートを読み取ってくれました。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Inkdropの&amp;quot;Tech Tips&amp;quot;から適切なflacファイルの作り方を検索して、示してください。&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;この指示により、以下の処理が自動実行されます。&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;search-notes&lt;&#x2F;code&gt;でキーワード検索&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;read-note&lt;&#x2F;code&gt;で該当ノートの内容取得&lt;&#x2F;li&gt;
&lt;li&gt;結果の整理と表示&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;h3 id=&quot;高度なワークフロー実演&quot;&gt;高度なワークフロー実演&lt;&#x2F;h3&gt;
&lt;p&gt;より複雑な処理として、ブログ記事の管理を試してみました。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;このブログプロジェクトから、2025年5月と6月の記事を確認して、&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;タイトル一覧をInkdropのInboxノートブックに新ノートとして作成してください。&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;この指示では以下の処理が連携して実行されました。&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;ファイルシステム分析&lt;&#x2F;strong&gt;：記事ディレクトリの探索&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;並列処理&lt;&#x2F;strong&gt;：5月・6月を別々のTaskエージェントで同時処理&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;内容解析&lt;&#x2F;strong&gt;：各記事のタイトル抽出とカテゴライズ&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;MCP統合&lt;&#x2F;strong&gt;：分析結果をInkdropに保存&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;結果として24記事（5月13件、6月11件）のタイトル一覧が自動的にカテゴリ別に整理され、Inkdropに新規ノートとして作成されました。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;セットアップのポイント&quot;&gt;セットアップのポイント&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;明示的指示の重要性&quot;&gt;明示的指示の重要性&lt;&#x2F;h3&gt;
&lt;p&gt;「Inkdropの...」という明示的な指示により、Claude CodeがMCPツールを確実に呼び出します。曖昧な指示では期待通りに動作しない場合があります。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;自動ツール選択&quot;&gt;自動ツール選択&lt;&#x2F;h3&gt;
&lt;p&gt;Claude Codeは文脈に応じて適切なMCPツールを自動選択し、複数のツールを連携させて処理を完了します。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;複合タスクの処理能力&quot;&gt;複合タスクの処理能力&lt;&#x2F;h3&gt;
&lt;p&gt;ファイルシステム分析、内容理解、MCP統合といった複合的なタスクを自動化できるのがClaude Codeの真の能力です。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;まとめ&quot;&gt;まとめ&lt;&#x2F;h2&gt;
&lt;p&gt;Claude CodeとInkdrop MCPの統合により、以下のメリットが得られます。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;コード開発中のメモ参照&lt;&#x2F;strong&gt;：開発中にInkdropのメモを即座に検索・参照可能&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;プロジェクト分析の自動化&lt;&#x2F;strong&gt;：コード分析結果の知識ベース化&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;ワークフローの完全自動化&lt;&#x2F;strong&gt;：複雑な処理を単一の指示で実行&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;MCP_を軸とした_Claude_連携の実例&quot;&gt;MCP を軸とした Claude 連携の実例&lt;&#x2F;h3&gt;
&lt;p&gt;実は、この記事の制作プロセス自体がMCP統合の真価を示しています。&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Claude Desktop での検証設計&lt;&#x2F;strong&gt;：セットアップ手順の相談と検証方法の策定&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Claude Desktop による知識蓄積&lt;&#x2F;strong&gt;：検証結果をMCP経由でInkdropのノートに整理・保存&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Claude Code による記事生成&lt;&#x2F;strong&gt;：MCP経由でInkdropから検証ノートを読み込み、ブログ記事として再構成&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;このワークフローでは、Claude DesktopとClaude Codeが同一のInkdropをMCPサーバーとして共有し、知識の橋渡し役として機能しています。単体のツール利用では不可能な、複数のClaude環境を跨いだ継続的な作業が実現されています。&lt;&#x2F;p&gt;
&lt;p&gt;この統合は、開発プロセスにおける知識管理と自動化の新しい可能性を示しており、MCPを軸としたClaudeエコシステムの真の価値がここにあります。&lt;&#x2F;p&gt;
</content>
        <summary type="html">Claude CodeでInkdrop MCPサーバーを設定し、リモートMCPサーバーとして統合する手順を詳しく解説します。実際のセットアップから高度なワークフローの実演まで、ステップバイステップで紹介。</summary>
        </entry><entry xml:lang="en">
        <title>AWSからSMSにメッセージを送る</title>
        <published>2025-06-09T00:00:00+00:00</published>
        <updated>2025-06-09T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2025/06/aws-sns/" type="text/html"/>
        <id>https://codedchords.dev/blog/2025/06/aws-sns/</id>
        
            <content type="html">&lt;h2 id=&quot;機密文書のメールでの共有&quot;&gt;機密文書のメールでの共有&lt;&#x2F;h2&gt;
&lt;p&gt;職場では取引先に資料を送付するのに暗号化したZIPでメールし、
パスワードを電話で伝えるということをやっているようです。
最低限のPPAP対策ですが、前時代的ですね。
当然ですが、先方から「電話で伝えられても困る」とよくクレームを受けているようです。
フィアル送信サービスも使っているようですが、「セキュリティ」と言う観点では何
の解決にもなっていません。&lt;&#x2F;p&gt;
&lt;p&gt;メールで機密文書を送る方法について、
現実的な選択肢を考えると以下のような評価かなと思います。&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;手段&lt;&#x2F;th&gt;&lt;th&gt;秘匿性（＝パスワードが第三者に見えないか）&lt;&#x2F;th&gt;&lt;th&gt;本人確認性（正しい相手か）&lt;&#x2F;th&gt;&lt;th&gt;コメント&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;① 暗号化ファイル、またはクラウドストレージ（認証なし） + パスワードを同じメールで送信&lt;&#x2F;td&gt;&lt;td&gt;❌：1通盗まれればすべて漏洩&lt;&#x2F;td&gt;&lt;td&gt;❌&lt;&#x2F;td&gt;&lt;td&gt;PPAPの典型。秘匿性は完全に破綻&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;② 暗号化ファイル、またはクラウドストレージ（認証なし） + パスワードを別メールで送信&lt;&#x2F;td&gt;&lt;td&gt;△：通信経路は一応分離だが同一インフラ内&lt;&#x2F;td&gt;&lt;td&gt;❌&lt;&#x2F;td&gt;&lt;td&gt;傍受・誤送信時に漏洩リスク高&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;③ 暗号化ファイル、またはクラウドストレージ（認証なし） + パスワードをSMSで送信&lt;&#x2F;td&gt;&lt;td&gt;◯：通信経路分離、実効性あり&lt;&#x2F;td&gt;&lt;td&gt;◯：端末本人であれば高い&lt;&#x2F;td&gt;&lt;td&gt;現実的な最低限の安全策&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;④ クラウドストレージ（認証あり）で共有&lt;&#x2F;td&gt;&lt;td&gt;◎：パスワード共有不要、URL単体では無効&lt;&#x2F;td&gt;&lt;td&gt;◎：ログインが必要なため本人限定&lt;&#x2F;td&gt;&lt;td&gt;アクセス制限・ログ取得が可能&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;⑤ S&#x2F;MIME暗号化メール&lt;&#x2F;td&gt;&lt;td&gt;◎：メール本文と添付がエンドツーエンドで暗号化&lt;&#x2F;td&gt;&lt;td&gt;◎：証明書により本人性確保&lt;&#x2F;td&gt;&lt;td&gt;導入済の組織間では最適解&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;⑥ GPG暗号メール &#x2F; 公開鍵暗号によるファイル送信&lt;&#x2F;td&gt;&lt;td&gt;◎：パスワード共有不要&lt;&#x2F;td&gt;&lt;td&gt;△：鍵配布と運用に依存&lt;&#x2F;td&gt;&lt;td&gt;高い秘匿性だが一般業務には難しい&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;h2 id=&quot;パスワードを別メールで送信&quot;&gt;パスワードを別メールで送信&lt;&#x2F;h2&gt;
&lt;p&gt;本来はS&#x2F;MIMEやGPGを検討すべきでしょうが、S&#x2F;MIMEの費用捻出が難しく、GPGを使う
リテラシーも無いので、次善の策としてSMSでパスワード送信は経路分離できている
分マシだと思いました。&lt;&#x2F;p&gt;
&lt;p&gt;以下はメールとは別の手段でパスワードを伝えるだけならばPC上からこうやってSMSにメッセージを送ることもできますよというデモです。
GUIから任意の電話番号にSMSを送信できます。&lt;&#x2F;p&gt;
&lt;p&gt;Pythonの実行環境が必要です。&lt;&#x2F;p&gt;
&lt;p&gt;処理概要です。あくまでデモです。&lt;&#x2F;p&gt;


&lt;noscript&gt;
    &lt;strong&gt;⚠️ JavaScript is required to render the diagram.&lt;&#x2F;strong&gt;
&lt;&#x2F;noscript&gt;
&lt;pre class=&quot;mermaid invertible-image&quot;&gt;
    graph TD
A[ユーザー]--&gt; B[Python GUIアプリケーション]
B --&gt; C[.env.localファイル]
C --&gt; D[AWS認証情報&lt;br&#x2F;&gt;ACCESS_KEY_ID&lt;br&#x2F;&gt;SECRET_ACCESS_KEY&lt;br&#x2F;&gt;REGION]

    B --&gt; E[電話番号入力&lt;br&#x2F;&gt;+81XXXXXXXXX]
    B --&gt; F[メッセージ入力&lt;br&#x2F;&gt;パスワード等]
    B --&gt; G[送信ボタン]

    G --&gt; H[boto3 SDK]
    H --&gt; I[AWS SNS API]
    I --&gt; J{SMS Sandbox?}

    J --&gt;|Sandbox Mode| K[検証済み番号のみ]
    J --&gt;|Production Mode| L[全世界の番号]

    K --&gt; M[国内キャリア&lt;br&#x2F;&gt;DoCoMo&#x2F;au&#x2F;SoftBank]
    L --&gt; M

    M --&gt; N[受信者の携帯電話]

    I --&gt; O[CloudWatch Logs]
    O --&gt; P[配信ログ&lt;br&#x2F;&gt;成功&#x2F;失敗&#x2F;料金]

    Q[料金] --&gt; R[$0.06-0.1&#x2F;SMS&lt;br&#x2F;&gt;約6-10円&#x2F;通]

    subgraph &quot;ローカル環境&quot;
        B
        C
    end

    subgraph &quot;AWS Cloud&quot;
        I
        J
        O
        P
    end

    subgraph &quot;日本国内&quot;
        M
        N
    end
    style A fill:#e1f5fe
    style B fill:#f3e5f5
    style I fill:#fff3e0
    style N fill:#e8f5e8
    style R fill:#ffebee
&lt;&#x2F;pre&gt;
&lt;p&gt;実際に任意のSMSに送信するには、AWSの管理コンソールでSANDBOXを解除する必要が
あります。また、このままだとユーザー認証していないので誰でも送信できてし
まいます。実際にシステムで行うには、認証した上でログを取得し監査できる状態に
するべきでしょう。&lt;&#x2F;p&gt;
&lt;p&gt;またSMSなので料金が発生します。&lt;&#x2F;p&gt;
&lt;p&gt;こんなことやるくらいなら&lt;strong&gt;さっさと S&#x2F;MINE をちゃんと導入しろよ&lt;&#x2F;strong&gt;と思います。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;ソースコード＆設定&quot;&gt;ソースコード＆設定&lt;&#x2F;h2&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;python&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-function z-builtin z-python&quot;&gt;print&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;アプリケーション開始&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;class&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; SNSSender&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-python&quot;&gt;    def&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-magic z-python&quot;&gt; __init__&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-function z-language z-special z-self z-python&quot;&gt;self&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;):&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-function z-builtin z-python&quot;&gt;        print&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;SNSSender初期化中...&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-control z-flow z-python&quot;&gt;        try&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable z-language z-special z-self z-python&quot;&gt;            self&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;sns&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; boto3&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;client&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;                &amp;quot;sns&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt; region_name&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;ap-northeast-1&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;            )&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;  # 東京リージョン&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-function z-builtin z-python&quot;&gt;            print&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;AWS SNSクライアント作成完了&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-control z-flow z-python&quot;&gt;        except&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-exception z-python&quot;&gt; Exception&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-control z-flow z-python&quot;&gt; as&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; e&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-function z-builtin z-python&quot;&gt;            print&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-string z-python&quot;&gt;f&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&amp;quot;AWS SNSクライアント作成エラー: &lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-format z-placeholder z-other z-python&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;e&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-format z-placeholder z-other z-python&quot;&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable z-language z-special z-self z-python&quot;&gt;            self&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;sns&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language z-python&quot;&gt; None&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable z-language z-special z-self z-python&quot;&gt;        self&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;setup_gui&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-python&quot;&gt;    def&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; setup_gui&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-function z-language z-special z-self z-python&quot;&gt;self&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;):&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-function z-builtin z-python&quot;&gt;        print&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;GUI設定中...&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable z-language z-special z-self z-python&quot;&gt;        self&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;root&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; tk&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;Tk&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable z-language z-special z-self z-python&quot;&gt;        self&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;root&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;title&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;AWS SNS SMS送信ツール&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable z-language z-special z-self z-python&quot;&gt;        self&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;root&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;geometry&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;500x400&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;        # 電話番号入力&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;        tk&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;Label&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-language z-special z-self z-python&quot;&gt;self&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;root&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt; text&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;電話番号 (+81XXXXXXXXX):&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt; font&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;Arial&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 12&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)).&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;pack&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt;            pady&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;10&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;        )&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable z-language z-special z-self z-python&quot;&gt;        self&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;phone_entry&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; tk&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;Entry&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-language z-special z-self z-python&quot;&gt;self&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;root&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt; width&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;30&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt; font&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;Arial&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 11&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;))&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable z-language z-special z-self z-python&quot;&gt;        self&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;phone_entry&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;pack&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt;pady&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;5&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;        # メッセージ入力&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;        tk&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;Label&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-language z-special z-self z-python&quot;&gt;self&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;root&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt; text&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;メッセージ:&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt; font&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;Arial&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 12&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)).&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;pack&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt;pady&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;20&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 5&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;))&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable z-language z-special z-self z-python&quot;&gt;        self&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;message_entry&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; tk&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;Text&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-language z-special z-self z-python&quot;&gt;self&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;root&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt; height&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;8&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt; width&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;50&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt; font&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;Arial&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 10&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;))&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable z-language z-special z-self z-python&quot;&gt;        self&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;message_entry&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;pack&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt;pady&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;5&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;        # 送信ボタン&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;        tk&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;Button&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable z-language z-special z-self z-python&quot;&gt;            self&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;root&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt;            text&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;SMS送信&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt;            command&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-language z-special z-self z-python&quot;&gt;self&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;send_sms&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt;            bg&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;blue&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt;            fg&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;white&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt;            font&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;Arial&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 12&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt;            padx&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;20&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt;            pady&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;10&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;        ).&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;pack&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt;pady&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;20&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;        # 結果表示&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable z-language z-special z-self z-python&quot;&gt;        self&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;result_label&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; tk&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;Label&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable z-language z-special z-self z-python&quot;&gt;            self&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;root&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt; text&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt; font&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;Arial&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 10&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;),&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt; wraplength&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;400&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;        )&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable z-language z-special z-self z-python&quot;&gt;        self&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;result_label&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;pack&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt;pady&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;10&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-function z-builtin z-python&quot;&gt;        print&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;GUI設定完了&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-python&quot;&gt;    def&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; send_sms&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-function z-language z-special z-self z-python&quot;&gt;self&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;):&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-function z-builtin z-python&quot;&gt;        print&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;SMS送信ボタンがクリックされました&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;        phone_number&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-language z-special z-self z-python&quot;&gt; self&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;phone_entry&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;get&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;().&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;strip&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;        message&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-language z-special z-self z-python&quot;&gt; self&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;message_entry&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;get&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;1.0&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt; tk&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;END&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;).&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;strip&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-function z-builtin z-python&quot;&gt;        print&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-string z-python&quot;&gt;f&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&amp;quot;電話番号: &lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-format z-placeholder z-other z-python&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;phone_number&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-format z-placeholder z-other z-python&quot;&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-function z-builtin z-python&quot;&gt;        print&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-string z-python&quot;&gt;f&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&amp;quot;メッセージ: &lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-format z-placeholder z-other z-python&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;message&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-format z-placeholder z-other z-python&quot;&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-control z-flow z-python z-keyword z-operator z-logical z-python&quot;&gt;        if not&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; phone_number&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable z-language z-special z-self z-python&quot;&gt;            self&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;result_label&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;config&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt;text&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;電話番号を入力してください&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt; fg&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;red&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-control z-flow z-python&quot;&gt;            return&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-control z-flow z-python z-keyword z-operator z-logical z-python&quot;&gt;        if not&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; message&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable z-language z-special z-self z-python&quot;&gt;            self&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;result_label&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;config&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt;text&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;メッセージを入力してください&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt; fg&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;red&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-control z-flow z-python&quot;&gt;            return&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-control z-flow z-python&quot;&gt;        if&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-language z-special z-self z-python&quot;&gt; self&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;sns&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-logical z-python&quot;&gt; is&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language z-python&quot;&gt; None&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable z-language z-special z-self z-python&quot;&gt;            self&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;result_label&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;config&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt;text&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;AWS接続エラー&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt; fg&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;red&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-control z-flow z-python&quot;&gt;            return&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-control z-flow z-python&quot;&gt;        try&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-function z-builtin z-python&quot;&gt;            print&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;SMS送信中...&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;            response&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-language z-special z-self z-python&quot;&gt; self&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;sns&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;publish&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt;                PhoneNumber&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;phone_number&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt;                Message&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;message&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt;                MessageAttributes&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;                    &amp;quot;AWS.SNS.SMS.SMSType&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;: {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;                        &amp;quot;DataType&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;String&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;                        &amp;quot;StringValue&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;Transactional&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;                    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;                },&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;            )&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;            message_id&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-indexed-name z-python&quot;&gt; response&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;MessageId&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;            success_text&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-string z-python&quot;&gt; f&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&amp;quot;送信完了！&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;Message ID: &lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-format z-placeholder z-other z-python&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;message_id&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-format z-placeholder z-other z-python&quot;&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable z-language z-special z-self z-python&quot;&gt;            self&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;result_label&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;config&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt;text&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;success_text&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt; fg&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;green&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-function z-builtin z-python&quot;&gt;            print&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-string z-python&quot;&gt;f&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&amp;quot;送信成功: &lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-format z-placeholder z-other z-python&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;message_id&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-format z-placeholder z-other z-python&quot;&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-control z-flow z-python&quot;&gt;        except&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-exception z-python&quot;&gt; Exception&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-control z-flow z-python&quot;&gt; as&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; e&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;            error_text&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-string z-python&quot;&gt; f&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&amp;quot;送信エラー:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape z-constant z-character z-format z-placeholder z-other z-python&quot;&gt;\n{&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-python&quot;&gt;str&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;e&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-format z-placeholder z-other z-python&quot;&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable z-language z-special z-self z-python&quot;&gt;            self&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;result_label&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;config&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt;text&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;error_text&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt; fg&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;red&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-function z-builtin z-python&quot;&gt;            print&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-string z-python&quot;&gt;f&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&amp;quot;送信エラー: &lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-format z-placeholder z-other z-python&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;e&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-format z-placeholder z-other z-python&quot;&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-python&quot;&gt;    def&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; run&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-function z-language z-special z-self z-python&quot;&gt;self&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;):&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-function z-builtin z-python&quot;&gt;        print&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;GUIメインループ開始&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable z-language z-special z-self z-python&quot;&gt;        self&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;root&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;mainloop&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-function z-builtin z-python&quot;&gt;        print&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;GUIメインループ終了&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# メイン実行&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-control z-flow z-python&quot;&gt;if&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-variable z-magic z-python&quot;&gt; __name__&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; ==&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;__main__&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    app&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt; SNSSender&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    app&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;run&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;AWSのIAMでアクセスキーを作成して、&lt;code&gt;.env.local&lt;&#x2F;code&gt;などに保存しておきます。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;AWS_ACCESS_KEY_ID=A@@@@@@@@@@@@@@@@&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;AWS_SECRET_ACCESS_KEY=@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;AWS_DEFAULT_REGION=ap-northeast-1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;</content>
        <summary type="html">AWSが提供するAmazon SNS(Simple Notification Service)を使って、SMSにメッセージを送信するサンプルコードを作ってみました。</summary>
        </entry><entry xml:lang="en">
        <title>Webサイト脆弱性スキャン入門：NucleiとKatanaで始めるセキュリティチェック</title>
        <published>2025-06-04T00:00:00+00:00</published>
        <updated>2025-06-04T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2025/06/vulnerability-check/" type="text/html"/>
        <id>https://codedchords.dev/blog/2025/06/vulnerability-check/</id>
        
            <content type="html">&lt;details&gt;
&lt;summary&gt;Table of Contents&lt;&#x2F;summary&gt;
&lt;!-- toc --&gt;
&lt;&#x2F;details&gt;
ebサイトのセキュリティが気になるけど、専門的な知識がなくて何から始めればいいか分からない...そんなIT技術者の方に向けて、オープンソースのツールを使った脆弱性スキャンの方法をご紹介します。今回は「Nuclei」と「Katana」という2つのツールを組み合わせて、効率的にWebサイトの脆弱性をチェックする方法を解説していきます。
&lt;h2 id=&quot;1._NucleiとKatanaとは？&quot;&gt;1. NucleiとKatanaとは？&lt;&#x2F;h2&gt;
&lt;p&gt;NucleiはProjectDiscoveryが開発したオープンソースの脆弱性スキャナーです。最大の特徴は以下の通りです。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;テンプレートベース&lt;&#x2F;strong&gt;：YAML形式のテンプレートで脆弱性パターンを定義&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;コミュニティ駆動&lt;&#x2F;strong&gt;：世界中のセキュリティ研究者が3000以上のテンプレートを提供&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;高速処理&lt;&#x2F;strong&gt;：並列処理による効率的なスキャン&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;低い誤検出率&lt;&#x2F;strong&gt;：実際の脆弱性を模擬したテストで精度が高い&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;多様な対応&lt;&#x2F;strong&gt;：CVE、設定ミス、情報漏洩など幅広い脆弱性に対応&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;KatanaもProjectDiscoveryが開発したWebクローラーです。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;高速クロール&lt;&#x2F;strong&gt;：Go言語で開発された軽量高速なクローラー&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;JavaScript対応&lt;&#x2F;strong&gt;：SPA（Single Page Application）も適切にクロール&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;設定柔軟&lt;&#x2F;strong&gt;：クロール深度や対象範囲を細かく制御可能&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Nuclei連携&lt;&#x2F;strong&gt;：同じ開発元のため、Nucleiとの相性が抜群&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;両者ともProjectDiscoveryが開発したツールですが、この組み合わせが良い理由は次
の通りです。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Katanaでサイト全体のURLを収集&lt;&#x2F;li&gt;
&lt;li&gt;NucleiでそれらのURLに対して脆弱性をチェック&lt;&#x2F;li&gt;
&lt;li&gt;両ツールとも同じ開発元なので連携がスムーズ&lt;&#x2F;li&gt;
&lt;li&gt;オープンソースなので無料で利用可能&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;2._インストール方法&quot;&gt;2. インストール方法&lt;&#x2F;h2&gt;
&lt;p&gt;前提条件は次の通りです。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;macOS&lt;&#x2F;li&gt;
&lt;li&gt;Homebrew（未インストールの場合は&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;brew.sh&#x2F;ja&#x2F;&quot;&gt;公式サイト&lt;&#x2F;a&gt;からインストール）&lt;&#x2F;li&gt;
&lt;li&gt;Go言語環境（&lt;code&gt;brew install go&lt;&#x2F;code&gt;でインストール可能）&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;インストール手順は以下の通りです。
初回実行時にNucleiが自動的にテンプレートをダウンロードします。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# Homebrewを使用（推奨）&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;brew&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; install nuclei&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# インストール確認&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;nuclei&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; -version&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# Go言語でインストール&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;go&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; install github.com&#x2F;projectdiscovery&#x2F;katana&#x2F;cmd&#x2F;katana@latest&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# インストール確認&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;katana&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; -version&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# テンプレートの手動更新（定期的に実行推奨）&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;nuclei&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; -update-templates&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;3._実行方法と結果の確認&quot;&gt;3. 実行方法と結果の確認&lt;&#x2F;h2&gt;
&lt;p&gt;最もシンプルな使い方から始めましょう。単一のURLを検査する方法です。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# 基本的なスキャン&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;nuclei&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; -u https:&#x2F;&#x2F;example.com -o results.txt&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# 重要度の高い脆弱性のみチェック&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;nuclei&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; -u https:&#x2F;&#x2F;example.com -s critical,high,medium -o important_vulns.txt&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;サイト全体をチェックしたい場合は、次のような手順となります。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# 1. Katanaでサイト全体をクロール&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;katana&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; -u https:&#x2F;&#x2F;example.com -d&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 2&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; -o urls.txt&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# 2. 不要なファイルを除外&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;grep&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt; -v -E &amp;#39;\.(jpg|jpeg|png|gif|css|js|ico)$&amp;#39; urls.txt&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; &amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; filtered_urls.txt&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# 3. Nucleiで脆弱性スキャン&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;nuclei&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; -l filtered_urls.txt -s critical,high,medium -o vulnerability_report.txt&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;脆弱性が発見されなければ何も出力されません。
脆弱性が発見された場合は発見された内容が出力されていますので、以下のように
確認できます。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# 発見された脆弱性の数&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;wc&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; -l vulnerability_report.txt&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# 脆弱性の内容確認&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;cat&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; vulnerability_report.txt&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# 重要度別の集計&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;cat&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; vulnerability_report.txt&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; |&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; grep&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt; -oE &amp;#39;\[(critical|high|medium|low)\]&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; |&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; sort&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; |&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; uniq&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; -c&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;4._どのような検証がなされているか確認する方法&quot;&gt;4. どのような検証がなされているか確認する方法&lt;&#x2F;h2&gt;
&lt;p&gt;仕事などで脆弱性検証する場合、「で、一体何が検証されたん？」と聞かれること
もあると思います。3,000以上のテンプレートを使用しているので、簡単にどんなテ
ンプレートが使用されているか把握する方法です。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# 全テンプレート数&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;nuclei&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; -tl&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; |&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; wc&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; -l&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# カテゴリ別のテンプレート数&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-function z-builtin&quot;&gt;echo&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;CVE脆弱性: &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;$(&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;nuclei&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; -tl -tags cve&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; |&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; wc&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; -l&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-function z-builtin&quot;&gt;echo&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;情報漏洩: &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;$(&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;nuclei&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; -tl -tags exposure&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; |&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; wc&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; -l&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-function z-builtin&quot;&gt;echo&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;設定ミス: &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;$(&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;nuclei&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; -tl -tags misconfig&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; |&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; wc&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; -l&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-function z-builtin&quot;&gt;echo&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;XSS: &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;$(&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;nuclei&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; -tl -tags xss&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; |&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; wc&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; -l&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-function z-builtin&quot;&gt;echo&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;LFI: &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;$(&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;nuclei&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; -tl -tags lfi&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; |&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; wc&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; -l&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-function z-builtin&quot;&gt;echo&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;管理画面: &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;$(&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;nuclei&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; -tl -tags panel&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; |&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; wc&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; -l&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-function z-builtin&quot;&gt;echo&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;技術スタック: &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;$(&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;nuclei&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; -tl -tags tech&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; |&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; wc&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; -l&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-function z-builtin&quot;&gt;echo&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;情報収集: &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;$(&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;nuclei&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; -tl -tags osint&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; |&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; wc&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; -l&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# 重要度で判別&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;nuclei&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; -tl -s critical&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; |&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; wc&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; -l&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;     # 1321件&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;nuclei&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; -tl -s high&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; |&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; wc&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; -l&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;         # 2377件&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;nuclei&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; -tl -s medium&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; |&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; wc&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; -l&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;       # 2322件&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;nuclei&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; -tl -s low&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; |&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; wc&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; -l&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;          # 316件&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;nuclei&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; -tl -s info&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; |&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; wc&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; -l&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;         # 4086件&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;脆弱性が発見された場合は、以下のように詳細ログを確認しましょう。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# 詳細ログ付きで実行&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;nuclei&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; -u https:&#x2F;&#x2F;example.com -v -o results.txt&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# 特定カテゴリのテンプレート一覧&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;nuclei&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; -tl -tags cve&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; |&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; head&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; -10&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;CVE（Common_Vulnerabilities_and_Exposures）について&quot;&gt;CVE（Common Vulnerabilities and Exposures）について&lt;&#x2F;h3&gt;
&lt;p&gt;CVEは世界共通のセキュリティ脆弱性カタログです。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;命名規則&lt;&#x2F;strong&gt;：CVE-YYYY-NNNNN（年-通し番号）&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;例&lt;&#x2F;strong&gt;：CVE-2021-44228（Log4jの重大な脆弱性）&lt;&#x2F;li&gt;
&lt;li&gt;Nucleiは3000以上のCVEに対応したテンプレートを保有&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;5._実践的な使い分け&quot;&gt;5. 実践的な使い分け&lt;&#x2F;h2&gt;
&lt;p&gt;実践的な使い方をまとめてみしょう。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# クイックチェック（30秒以内）&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;nuclei&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; -u https:&#x2F;&#x2F;example.com -t exposures&#x2F; -s critical,high&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# バランス型チェック（1-2分）&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;nuclei&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; -u https:&#x2F;&#x2F;example.com -t cves&#x2F;,exposures&#x2F; -s medium,high,critical&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# 徹底スキャン（5-10分） - 新サイトの評価など&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;katana&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; -u https:&#x2F;&#x2F;example.com -d&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 2&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; |&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; nuclei&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; -s critical,high,medium&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;テンプレート選択は以下のような指針で運用するとよいと思います。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;初回チェック&lt;&#x2F;strong&gt;：&lt;code&gt;cves&#x2F;,exposures&#x2F;&lt;&#x2F;code&gt;（CVEと情報漏洩）&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;定期チェック&lt;&#x2F;strong&gt;：&lt;code&gt;-s critical,high&lt;&#x2F;code&gt;（重要度の高いもののみ）&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;詳細調査&lt;&#x2F;strong&gt;：全テンプレート使用&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;6._パフォーマンス最適化&quot;&gt;6. パフォーマンス最適化&lt;&#x2F;h2&gt;
&lt;p&gt;脆弱性の検証自体は結構重たい処理なってしまうので、パフォーマンスが問題となる
場合は、以下のような並行度やレート制限を調整しましょう。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# 並列度とレート制限の調整&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;nuclei&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; -u https:&#x2F;&#x2F;example.com -c&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 50&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; -rl&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 100&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; -timeout&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 5&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# バッチ処理での最適化&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;nuclei&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; -l urls.txt -c&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 25&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; -rl&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 50&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; -bulk-size&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 25&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;-c 50&lt;&#x2F;strong&gt;：同時実行テンプレート数を50に設定&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;-rl 100&lt;&#x2F;strong&gt;：1秒間に100リクエストまで&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;-timeout 5&lt;&#x2F;strong&gt;：タイムアウトを5秒に短縮&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;7._セキュリティ向上のための継続的運用&quot;&gt;7. セキュリティ向上のための継続的運用&lt;&#x2F;h2&gt;
&lt;p&gt;継続的に運用するために、次のようなスクリプトを組んでcronなどで自動運用する
方法もよいと思います。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-shebang z-shell z-meta z-shebang z-shell&quot;&gt;#!&#x2F;bin&#x2F;bash&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# daily_security_check.sh&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;TARGET&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;https:&#x2F;&#x2F;your-website.com&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;DATE&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;$(&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;date&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; +%Y%m%d&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;OUTPUT_DIR&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;security_scans&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-normal z-shell&quot;&gt;$DATE&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# 金曜日（5）かチェック&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;if&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; [ $(&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;date&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; +%u&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; -eq&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 5&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; ];&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; then&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-function z-builtin&quot;&gt;    echo&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;金曜日なので、テンプレートを更新します...&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;    nuclei&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; -update-templates&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;fi&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;mkdir&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt; -p &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-normal z-shell&quot;&gt;$OUTPUT_DIR&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# 高優先度の脆弱性をチェック&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;nuclei&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt; -u &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-normal z-shell&quot;&gt;$TARGET&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot; -s critical,high -o &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-normal z-shell&quot;&gt;$OUTPUT_DIR&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt;&#x2F;critical_scan.txt&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# 結果をメール送信（お好みで）&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;if&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; -s&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-normal z-shell&quot;&gt;$OUTPUT_DIR&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt;&#x2F;critical_scan.txt&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; ];&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; then&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;    mail&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt; -s &amp;quot;セキュリティアラート: &lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-normal z-shell&quot;&gt;$TARGET&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot; admin@company.com&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; &amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-normal z-shell&quot;&gt;$OUTPUT_DIR&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt;&#x2F;critical_scan.txt&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;fi&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;8._他ツールとの連携例&quot;&gt;8. 他ツールとの連携例&lt;&#x2F;h2&gt;
&lt;p&gt;Webサイトが静的サイトジェネレーターなどで組まれている場合は、
サイト生成のCI&#x2F;CDパイプラインに脆弱性検証を組み込むという手もあります。&lt;&#x2F;p&gt;
&lt;p&gt;以下は、GitHub Actionsの例です。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;yaml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# GitHub Actions例&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;name&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; Security Scan&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-constant z-language z-boolean&quot;&gt;on&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;  schedule&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    -&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt; cron&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;0 9 * * 1&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt; # 毎週月曜日9時&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;jobs&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;  security-scan&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;    runs-on&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; ubuntu-latest&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;    steps&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;      -&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt; uses&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; actions&#x2F;checkout@v2&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;      -&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt; name&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; Install Nuclei&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;        run&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; |&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;          go install github.com&#x2F;projectdiscovery&#x2F;nuclei&#x2F;v3&#x2F;cmd&#x2F;nuclei@latest&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;      -&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt; name&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; Run Security Scan&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;        run&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; |&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;          nuclei -u ${{ secrets.TARGET_URL }} -s critical,high -o scan_results.txt&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;      -&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt; name&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; Upload Results&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;        uses&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; actions&#x2F;upload-artifact@v2&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;        with&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;          name&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; security-scan-results&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;          path&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; scan_results.txt&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;また、レポート生成の自動化、定期的な処理などの最後にレポート出力を組み込んで
も良いと思います。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# 簡単なサマリーレポート生成&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;generate_security_report&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;() {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    TARGET&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt;$1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    OUTPUT&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;security_report_&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;$(&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;date&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; +%Y%m%d&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt;.txt&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-function z-builtin&quot;&gt;    echo&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;=== セキュリティスキャンレポート ===&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; &amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-normal z-shell&quot;&gt;$OUTPUT&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-function z-builtin&quot;&gt;    echo&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;対象サイト: &lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-normal z-shell&quot;&gt;$TARGET&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; &amp;gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-normal z-shell&quot;&gt;$OUTPUT&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-function z-builtin&quot;&gt;    echo&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;スキャン日時: &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;$(&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;date&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; &amp;gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-normal z-shell&quot;&gt;$OUTPUT&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-function z-builtin&quot;&gt;    echo&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;quot;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; &amp;gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-normal z-shell&quot;&gt;$OUTPUT&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;    # スキャン実行&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;    nuclei&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt; -u &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-normal z-shell&quot;&gt;$TARGET&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot; -s critical,high,medium -o temp_results.txt&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-function z-builtin&quot;&gt;    echo&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;発見された脆弱性数: &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;$(&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;wc&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; -l&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; &amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; temp_results.txt&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; &amp;gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-normal z-shell&quot;&gt;$OUTPUT&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-function z-builtin&quot;&gt;    echo&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;quot;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; &amp;gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-normal z-shell&quot;&gt;$OUTPUT&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-function z-builtin&quot;&gt;    echo&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;詳細結果:&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; &amp;gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-normal z-shell&quot;&gt;$OUTPUT&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;    cat&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; temp_results.txt&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; &amp;gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-normal z-shell&quot;&gt;$OUTPUT&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;    rm&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; temp_results.txt&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-function z-builtin&quot;&gt;    echo&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;レポートを生成しました: &lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-normal z-shell&quot;&gt;$OUTPUT&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# 使用例&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;generate_security_report&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;https:&#x2F;&#x2F;example.com&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;⚠️_重要：責任ある使用のための注意事項&quot;&gt;⚠️ 重要：責任ある使用のための注意事項&lt;&#x2F;h2&gt;
&lt;p&gt;脆弱性の検証はサーバーに非常に負荷をかけるため、
不正アクセス禁止法、電子計算機損壊等業務妨害罪、偽計業務妨害罪
などに抵触し違法行為になる可能性があります。&lt;&#x2F;p&gt;
&lt;p&gt;必ず以下を遵守しましょう。&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;所有権の確認&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;自分が所有するサイトのみスキャンしてください&lt;&#x2F;li&gt;
&lt;li&gt;他者のサイトには必ず事前許可を取得してください&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;適切な負荷制御&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;本番サイトへの負荷を考慮してレート制限を設定&lt;&#x2F;li&gt;
&lt;li&gt;業務時間外でのスキャン実施を推奨&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;結果の適切な管理&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;スキャン結果に機密情報が含まれる可能性あり&lt;&#x2F;li&gt;
&lt;li&gt;結果ファイルの保存場所とアクセス権限に注意&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;h3 id=&quot;なぜ偽計業務妨害罪となる可能性があるか&quot;&gt;なぜ偽計業務妨害罪となる可能性があるか&lt;&#x2F;h3&gt;
&lt;p&gt;偽計業務妨害罪（刑法233条）の要件は、以下の3つです。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;偽計：虚偽の情報や人を欺く行為&lt;&#x2F;li&gt;
&lt;li&gt;業務妨害：他人の業務を妨害すること&lt;&#x2F;li&gt;
&lt;li&gt;故意：妨害する意図があること&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;脆弱性検査はサーバーに非常に負荷を掛ける処理であることは知られているので、
業務妨害と故意であることは分かりやすいと思います。&lt;&#x2F;p&gt;
&lt;p&gt;「偽計」については、脆弱性スキャンはブラウザの正常なアクセスを装って
リクエストヘッダを偽装しつつ「負荷」という観点では攻撃的とも言えるペイロード
を送信するため「偽計」と見なされる可能性があります。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;まとめ&quot;&gt;まとめ&lt;&#x2F;h2&gt;
&lt;p&gt;NucleiとKatanaを使った脆弱性スキャンは、以下のような方に特におすすめです。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;自社サイトのセキュリティ状況を定期的にチェックしたい&lt;&#x2F;li&gt;
&lt;li&gt;オープンソースツールでコストを抑えたい&lt;&#x2F;li&gt;
&lt;li&gt;コマンドラインツールに慣れている&lt;&#x2F;li&gt;
&lt;li&gt;セキュリティの基本的な知識を実践で学びたい&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;最初は単一URLの簡単なチェックから始めて、慣れてきたらサイト全体のスキャンや自動化に挑戦してみてください。重要なのは継続的にセキュリティをチェックする習慣を作ることです。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;脆弱性が見つからない結果も良い結果&lt;&#x2F;strong&gt;です。むしろサイトが適切にメンテナンスされている証拠として安心できる材料になります。&lt;&#x2F;p&gt;
&lt;p&gt;セキュリティは一度設定すれば終わりではなく、継続的な取り組みが重要です。このツールを活用して、より安全なWebサイト運営を目指しましょう。&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;&lt;strong&gt;参考リンク&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;docs.projectdiscovery.io&#x2F;opensource&#x2F;nuclei&#x2F;overview&quot;&gt;Nuclei公式ドキュメント&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;projectdiscovery&#x2F;katana&quot;&gt;Katana公式リポジトリ&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;projectdiscovery.io&#x2F;&quot;&gt;ProjectDiscovery&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;&lt;strong&gt;注意&lt;&#x2F;strong&gt;：この記事の内容は啓蒙目的であり、適切な許可なく他者のシステムをスキャンすることは違法行為となる可能性があります。必ず責任を持って使用してください。&lt;&#x2F;p&gt;
</content>
        <summary type="html">ebサイトのセキュリティが気になるけど、専門的な知識がなくて何から始めればいいか分からない...そんなIT技術者の方に向けて、オープンソースのツールを使った脆弱性スキャンの方法をご紹介します。今回は「Nuclei」と「Katana」という2つのツールを組み合わせて、効率的にWebサイトの脆弱性をチェックする方法を解説していきます。</summary>
        </entry><entry xml:lang="en">
        <title>Anthropic Claude4を発表</title>
        <published>2025-05-23T00:00:00+00:00</published>
        <updated>2025-05-23T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2025/05/claude4/" type="text/html"/>
        <id>https://codedchords.dev/blog/2025/05/claude4/</id>
        
            <content type="html">&lt;p&gt;Anthropicが開発者会議「Code with Claude」で推論能力と深い思考能力が大きく向上した新しいモデルClaude 4を発表しました。&lt;&#x2F;p&gt;
&lt;details&gt;
&lt;summary&gt;Table of Contens&lt;&#x2F;summary&gt;
&lt;!-- toc --&gt;
&lt;&#x2F;details&gt;
&lt;h2 id=&quot;Claude_4_の内容&quot;&gt;Claude 4 の内容&lt;&#x2F;h2&gt;
&lt;p&gt;Anthropicは2月に前世代の「Claude Sonnet 3.7」をリリースしてばかりですが、
OpenAIが4月にコンテキストウィンドウを拡大した「GPT-4.1」や、新しい推論モデル「o3」「o4-mini」を公開するなど
競合のAI開発企業も性能を引き上げているのに対抗して早期に新しいモデル投入して
きたのだと思います。&lt;&#x2F;p&gt;
&lt;p&gt;まずはClaude Sonnet 3.7を基に改良を加えた&lt;strong&gt;Claude Sonnet 4&lt;&#x2F;strong&gt;です。
Sonnet3.7では過度に積極的な回答をする場合があったようですが、
今回Sonnet 4では適度に軽量化されているようです。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Claude Opus 4&lt;&#x2F;strong&gt;はより大規模で計算資源を要するモデルで、
特に難易度の高い課題を処理できるよう設計されているようです。
人間であれば数時間かかる作業を同モデルが短時間でこなす性能を示しているそうで
す。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;Claude_4の検証&quot;&gt;Claude 4の検証&lt;&#x2F;h2&gt;
&lt;p&gt;中島聡氏が&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;SingularitySociety&#x2F;WorldModels&#x2F;&quot;&gt;Workd Models&lt;&#x2F;a&gt;
として公開している課題でいくつかテストしてみました。&lt;&#x2F;p&gt;
&lt;p&gt;「綿菓子の高さは８センチ、レンガの高さは７センチ。綿菓子の上にレンガを置くと
、高さは何センチ？」という課題に対して、それぞれの回答を確認してみましょう。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# Sonnet 3.7&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;この問題を解決するために、それぞれの高さを足し合わせます。&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;綿菓子の高さ: 8センチ&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;レンガの高さ: 7センチ&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;綿菓子の上にレンガを置いた場合の全体の高さ:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;8センチ + 7センチ = 15センチ&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;したがって、綿菓子の上にレンガを置くと、高さは15センチになります。&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# Opus 3&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;では、綿菓子の高さとレンガの高さを足し算して、全体の高さを求めましょう。&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;綿菓子の高さ: 8センチ&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;レンガの高さ: 7センチ&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;8センチ + 7センチ = 15センチ&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;したがって、綿菓子の上にレンガを置くと、高さは15センチになります。&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# Sonnet 4&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;綿菓子の高さ8センチの上にレンガの高さ7センチを置くと、合計の高さは&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;15センチになります。&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;8 + 7 = 15センチです。&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# Opus 4&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;綿菓子の上にレンガを置いた場合、綿菓子は軽くてふわふわしているため、&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;レンガの重さで押しつぶされてしまいます。綿菓子はほぼ完全に圧縮されて&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;しまうので、実質的な高さはレンガの高さである7センチになると考えられ&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;ます。&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# ChatGPT&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;綿菓子の上にレンガを置くと、綿菓子はつぶれてしまう可能性があります。&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;そのため、綿菓子の高さ8センチとレンガの高さ7センチを単純に足して15&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;センチとは限りません。&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;綿菓子は非常に柔らかく、重いレンガを置くとほとんど潰れてしまうこと&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;が多いです。もし綿菓子が完全につぶれたと仮定すると、高さはレンガの&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;高さだけの7センチになります。&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;よって、実際の高さは7センチより少し上程度（綿菓子がどれだけ潰れるか&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;による）と考えられます。&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;まとめ&quot;&gt;まとめ&lt;&#x2F;h2&gt;
&lt;p&gt;Claude 4の登場は、LLMの技術進化がもはや年単位ではなく「月単位」で進む時代に突入していることを改めて印象づけました。Sonnet 4は従来モデルの過剰応答傾向を抑制し、応答の一貫性・安定性を向上。一方、Opus 4は汎用的な知識応答を超え、タスクに応じた状況推論や人間的な判断に近づいています。&lt;&#x2F;p&gt;
&lt;p&gt;特に、綿菓子の課題のような「文脈理解」と「物理的直感」が求められるケースで、
Opus 4は従来の加算的な計算ではなく素材特性を踏まえた判断を下しています。
これは今後のエージェント系アプリケーションにも直結する進化です。&lt;&#x2F;p&gt;
&lt;p&gt;競合のChatGPT（GPT-4.1）も同様に高い水準にあり、両者はもはや単純な精度比較ではなく、「推論スタイル」や「コンテキスト処理のアプローチ」の差をどうプロダクトに活かすかが焦点になります。&lt;&#x2F;p&gt;
&lt;p&gt;Claude 4は「回答の速さ」や「正確さ」だけでは語りきれない次のフェーズに入りつつあり、開発者としては、タスクの性質や求める出力の粒度に応じたモデル選定の重要性が今後ますます増していくと感じました。&lt;&#x2F;p&gt;
</content>
        <summary type="html">Anthropic が開発者会議「Code with Claude」で推論能力と深い思考能力が大きく向上した新しいモデルClaude 4を発表しました。</summary>
        </entry><entry xml:lang="en">
        <title>NeoVimからClaude Codeを使う</title>
        <published>2025-05-04T00:00:00+00:00</published>
        <updated>2025-05-04T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2025/05/claude-code-nvim/" type="text/html"/>
        <id>https://codedchords.dev/blog/2025/05/claude-code-nvim/</id>
        
            <content type="html">&lt;!-- textlint-disable --&gt;
&lt;img
  src=&quot;https:&amp;#x2F;&amp;#x2F;codedchords.dev&amp;#x2F;blog&amp;#x2F;2025&amp;#x2F;05&amp;#x2F;claude-code-nvim&amp;#x2F;claude-code-nvim.webp?h=ef29ff190878e35e43bc&quot;
  alt=&quot;Claude-Code-Nvim&quot; width=&quot;1735&quot; height=&quot;1212&quot; loading=&quot;lazy&quot;
&#x2F;&gt;&lt;!-- textlint-enable --&gt;
&lt;p&gt;AnthropicのDeveloper Partner ProgramにJoinしてClaude Codeを使うモチベーションが高まっています。Claude CodeをNeoVimから使用するためのClaude Code Neovim Pluginをインストールしました。Claude Code Neovim PluginをNeoVimで使う方法を説明します。&lt;&#x2F;p&gt;
&lt;details&gt;
&lt;summary&gt;Table of Contents&lt;&#x2F;summary&gt;
&lt;!-- toc --&gt;
&lt;&#x2F;details&gt;
## Claude Code Neovim Plugin
&lt;p&gt;今回導入したのは、&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;greggh&#x2F;claude-code.nvim&quot;&gt;Claude Code Neovim Plugin&lt;&#x2F;a&gt; &lt;code&gt;claude-code.nvim&lt;&#x2F;code&gt; です。&lt;&#x2F;p&gt;
&lt;p&gt;基本的にやっていることはNeoVimのターミナルを使い、Claude Codeを呼び出してい
るようです。&lt;&#x2F;p&gt;
&lt;p&gt;次のような機能がサポートされます。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;ターミナルウィンドウでキー一押しだけでClaude Codeを切り替え&lt;&#x2F;li&gt;
&lt;li&gt;--continueなどのコマンドライン引数やカスタムバリアントのサポート&lt;&#x2F;li&gt;
&lt;li&gt;Claude Codeによって変更されたファイルを自動検出して再読み込み&lt;&#x2F;li&gt;
&lt;li&gt;ファイルが外部で変更された際のリアルタイムバッファ更新&lt;&#x2F;li&gt;
&lt;li&gt;カスタマイズ可能なウィンドウ位置とサイズ&lt;&#x2F;li&gt;
&lt;li&gt;which-key（利用可能な場合）との統合&lt;&#x2F;li&gt;
&lt;li&gt;作業ディレクトリとしてgitプロジェクトのルートを自動的に使用（利用可能な場合）&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;当たり前ですが、&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;anthropics&#x2F;claude-code&quot;&gt;Claude Code CLI&lt;&#x2F;a&gt;がインストールされている必要があります。&lt;&#x2F;p&gt;
&lt;p&gt;注意点としては、Claude Desktopなどを呼び出しているのでなく、Claude Codeを呼
び出しているため、　&lt;strong&gt;APIの使用料がかかります&lt;&#x2F;strong&gt;。 Claude APIでなくClaude
Codeをの呼び出しているため、Anthropic Developer Partner Programeのディスカウン
ト対象とはなります。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;claud-code.nvimのインストール&quot;&gt;&lt;code&gt;claud-code.nvim&lt;&#x2F;code&gt;のインストール&lt;&#x2F;h2&gt;
&lt;p&gt;私はプラグインマネージャーとして &lt;code&gt;lazy.nvim&lt;&#x2F;code&gt;を使っているので
以下の設定でインストール完了です。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;lua&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;return&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;  &amp;quot;greggh&#x2F;claude-code.nvim&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;  dependencies&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;    &amp;quot;nvim-lua&#x2F;plenary.nvim&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;, &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;-- Required for git operations&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;  },&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;  config&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; function&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-function&quot;&gt;    require&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;claude-code&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;).&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function&quot;&gt;setup&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;  end&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;claude-code.nvimの使い方&quot;&gt;&lt;code&gt;claude-code.nvim&lt;&#x2F;code&gt;の使い方&lt;&#x2F;h2&gt;
&lt;p&gt;このプラグインは先週インストールして試していたのですが、
今週になって起動方法が追加される名で週末に更新されていました。&lt;&#x2F;p&gt;
&lt;p&gt;基本的な機能は次の通りです。&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;機能&lt;&#x2F;th&gt;&lt;th&gt;コマンド&lt;&#x2F;th&gt;&lt;th&gt;キーアサイン&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;起動&lt;&#x2F;td&gt;&lt;td&gt;&lt;code&gt;:ClaudeCode&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;&lt;code&gt;&amp;lt;C-,&amp;gt;&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;最後の会話を再開&lt;&#x2F;td&gt;&lt;td&gt;:ClaudeCodeContinue&lt;&#x2F;td&gt;&lt;td&gt;&lt;code&gt;&amp;lt;leader&amp;gt;cC&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;会話ピッカーで選択して再開&lt;&#x2F;td&gt;&lt;td&gt;:ClaudeCodeResume&lt;&#x2F;td&gt;&lt;td&gt;N&#x2F;A&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Verboseモード&lt;&#x2F;td&gt;&lt;td&gt;&lt;code&gt;:ClaudeCodeVerbose&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;&lt;code&gt;&amp;lt;leader&amp;gt;cV&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;Claude Codeターミナルでは次のキーが使用できます。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;C-h&amp;gt;&lt;&#x2F;code&gt;,&lt;code&gt;&amp;lt;C-j&amp;gt;&lt;&#x2F;code&gt;,&lt;code&gt;&amp;lt;C-k&amp;gt;&lt;&#x2F;code&gt;,&lt;code&gt;&amp;lt;C-l&amp;gt;&lt;&#x2F;code&gt; : ウィンドウ間の移動&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;C-f&amp;gt;&lt;&#x2F;code&gt;,&lt;code&gt;&amp;lt;C-b&amp;gt;&lt;&#x2F;code&gt;: ページスクロール&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;まとめ&quot;&gt;まとめ&lt;&#x2F;h2&gt;
&lt;p&gt;今回はClaude CodeをNeoVimから直接使用できる &lt;code&gt;claude-code.nvim&lt;&#x2F;code&gt; プラグインを紹介しました。ターミナルからClaude Codeを呼び出す方法よりも、コーディング作業の流れを止めることなくAIの支援を受けられるようになります。&lt;&#x2F;p&gt;
&lt;p&gt;このプラグインを使うことで、NeoVim内で簡単にClaude Codeへアクセスでき、
シームレスなコードの修正や生成を行えるようになります。特にgitプロジェクトの
コンテキストを自動的に認識する機能は、大規模なプロジェクトでの作業に役立ちま
す。&lt;&#x2F;p&gt;
&lt;p&gt;一点注意が必要なのは、API使用料がかかる点です。ただし、Anthropic Developer Partner Programに参加している場合は割引が適用されるので、Claude APIを直接呼び出すより合理的です。コーディング効率向上のためのツールとして、検討する価値は十分にあるでしょう。&lt;&#x2F;p&gt;
</content>
        <summary type="html">Anthropic の Developer Partner Program に Join してClaude Codeを使うモチベーションが高まっています。Claude CodeをNeoVimから使用するためのClaude Code Neovim Pluginをインストールしました。Claude Code Neovim Plugin を NeoVim で使う方法を説明します。</summary>
        </entry><entry xml:lang="en">
        <title>Claude Codeのディスカウントを得る - Developer Partner Program</title>
        <published>2025-05-02T00:00:00+00:00</published>
        <updated>2025-05-02T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2025/05/anthropics-developer-partner-program/" type="text/html"/>
        <id>https://codedchords.dev/blog/2025/05/anthropics-developer-partner-program/</id>
        
            <content type="html">&lt;p&gt;Claude Code APIの利用料割引が可能となるDeveloper Partner ProgrameがAnthropicより発表されました。今後のモデル改善のためのプログラムで参加するとClaude 3.5 SonnetおよびClaude 3.7SonnetモデルのClaude Code入力トークンが30%割引になる可能性があります。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;Anthropic&amp;#39;s_Developer_Partner_Programのポイント&quot;&gt;Anthropic&#x27;s Developer Partner Programのポイント&lt;&#x2F;h2&gt;
&lt;p&gt;AnthropicのClaudeは基本的にユーザーの入力をトレーニングに使用しませんが、
この &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;support.anthropic.com&#x2F;en&#x2F;articles&#x2F;11174108-about-the-development-partner-program&quot;&gt;Anthropic&#x27;s Developer Partner Program&lt;&#x2F;a&gt; では、Anthropicのサービスやモデルトレーニングを改善
するために、Claude Codeセッションを自主的にAnthropicと共有することになります。&lt;&#x2F;p&gt;
&lt;p&gt;その代わりに、Claude 3.5 SonnetとClaude 3.7 SonnetのClaude Code入力トークンに対して、
標準API価格から30%オフを受けることができます。具体的には次の通りです。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;標準入力: 100万トークンあたり-$0.9&lt;&#x2F;li&gt;
&lt;li&gt;キャッシュ書き込み: 100万トークンあたり-$1.125&lt;&#x2F;li&gt;
&lt;li&gt;キャッシュ読み取り: 100万トークンあたり-$0.09&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;利用するに当たっては、次のような注意点があります。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;AnthropicのファーストパーティAPIからのClaude Codeの入出力トークンのみが共
有され、ClaudeアプリやClaude Code以外のAPI呼び出しには適用されない。
つまり、Amazon Bedrockなどを経由するとプログラムは適用されず割引の対象外である&lt;&#x2F;li&gt;
&lt;li&gt;データは最大2年間安全に保存される。モデルトレーニングに使用されるデータは
他の顧客情報と関連付けらない&lt;&#x2F;li&gt;
&lt;li&gt;この設定は組織内のすべてのメンバーに適用される&lt;&#x2F;li&gt;
&lt;li&gt;プログラムに登録した場合、組織内のすべてのメンバーに通知される&lt;&#x2F;li&gt;
&lt;li&gt;いつでもプログラムから離脱可能だが、以前に共有されたデータは削除不可&lt;&#x2F;li&gt;
&lt;li&gt;割引は請求後2025年7月31日まで適用され、プログラムを離脱すると終了する&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;プログラムへの参加方法&quot;&gt;プログラムへの参加方法&lt;&#x2F;h2&gt;
&lt;p&gt;AnthropicのConsoleの設定(Claudeの設定画面でないことに注意)から、
「Privacy Controls」を開いて「Join our Development Partner Program to help improve Claude」
で「Join」ボタンを押すだけです。&lt;&#x2F;p&gt;
&lt;p&gt;離脱時は、「Leave」ボタンが現れるので、押すとプログラムを離脱できます。&lt;&#x2F;p&gt;
&lt;p&gt;ただし、すべてのアカウントがこのプログラムの対象ではないようです。
アカウントが対象でない場合は、上記の参加オプションが表示されません。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;まとめ&quot;&gt;まとめ&lt;&#x2F;h2&gt;
&lt;p&gt;どれくらいの人がClaude Codeを使っているわかりませんが、GitHub Copilotのよう
「コード入力支援」を超えClaude Codeは優れた開発者とペアプログラミングしているような
錯覚に陥るほど生産性が上がります。&lt;&#x2F;p&gt;
&lt;p&gt;このため、Claude Codeの利用料が30%の割引となるのは魅力的です。
参加をためらうとしたら、「自身のコンテンツが学習に利用される」という
プライバシーの点でしょう。業務で利用している場合は、成果物が他社に共有される
ことになるためハードルが高そうです。&lt;&#x2F;p&gt;
&lt;p&gt;私自身は個人の活動で利用なので、プライバシーの観点での懸念はありません。
自身のClaude Codeセッションを共有することでClaudeのコーディング能力向上に
寄与し、AIによるコーディング支援技術の発展できることはモチベーションにも繋が
ります。
更に割引まで恩恵を受けることができるならば参加しない理由はないため、即座に参加しました。&lt;&#x2F;p&gt;
</content>
        <summary type="html">Claude Code APIの利用料割引が可能となるDeveloper Partner ProgrameがAnthropicより発表されました。今後のモデル改善のためのプログラムで参加するとClaude 3.5 Sonnet および Claude 3.7Sonnet モデルの Claude Code 入力トークンが30%割引になる可能性があります。</summary>
        </entry><entry xml:lang="en">
        <title>SoundCloud API仕様の変更</title>
        <published>2025-04-28T00:00:00+00:00</published>
        <updated>2025-04-28T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2025/04/soundcloud-api-changed/" type="text/html"/>
        <id>https://codedchords.dev/blog/2025/04/soundcloud-api-changed/</id>
        
            <content type="html">&lt;p&gt;直近数日の内にSoundCloudはAPIの仕様を変更したようです。自作のTypeScriptコンポーネントがうまく機能しなくなったために対応しました。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;変更のポイント&quot;&gt;変更のポイント&lt;&#x2F;h2&gt;
&lt;p&gt;以下のコードは以前使用していたものでSoundCloudの曲をWebに埋め込むためのコー
ドです。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-storage z-type&quot;&gt;export const&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; SoundCloudEmbed&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; React&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt;FC&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt;SoundCloudEmbedProps&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; ({&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt; url&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; })&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt; =&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;  &#x2F;&#x2F; SoundCloud の埋め込み URL 形式に変換&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;  const&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-constant z-js&quot;&gt; embedUrl&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; `https:&#x2F;&#x2F;w.soundcloud.com&#x2F;player&#x2F;?url=&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;${&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;encodeURIComponent&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt;url&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt;&amp;amp;color=%23ff5500&amp;amp;auto_play=false&amp;amp;hide_related=false&amp;amp;show_comments=true&amp;amp;show_user=true&amp;amp;show_reposts=false&amp;amp;show_teaser=true`&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;  return&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; (&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;    &amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;div&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-other z-attribute-name&quot;&gt; className&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;w-full&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;      &amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;iframe&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-other z-attribute-name&quot;&gt;        width&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;100%&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-other z-attribute-name&quot;&gt;        height&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;166&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-other z-attribute-name&quot;&gt;        scrolling&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;no&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-other z-attribute-name&quot;&gt;        frameBorder&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;no&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-other z-attribute-name&quot;&gt;        allow&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;autoplay&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-other z-attribute-name&quot;&gt;        src&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt;embedUrl&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;      &amp;gt;&amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;iframe&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;      &amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;div&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-other z-attribute-name&quot;&gt; className&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;text-[10px] text-gray-400 overflow-hidden whitespace-nowrap text-ellipsis font-light&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;        &amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;a&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-other z-attribute-name&quot;&gt;          href&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;https:&#x2F;&#x2F;soundcloud.com&#x2F;yostos&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-other z-attribute-name&quot;&gt;          title&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;Yostos&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-other z-attribute-name&quot;&gt;          target&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;_blank&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-other z-attribute-name&quot;&gt;          rel&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;noopener noreferrer&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-other z-attribute-name&quot;&gt;          className&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;text-gray-400 no-underline&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;        &amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;          Yostos&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;        &amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;a&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;        &amp;amp;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;nbsp&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;·&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;nbsp&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;        &amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;a&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-other z-attribute-name&quot;&gt;          href&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt;url&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-other z-attribute-name&quot;&gt;          title&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;Yostos&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-other z-attribute-name&quot;&gt;          target&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;_blank&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-other z-attribute-name&quot;&gt;          rel&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;noopener noreferrer&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-other z-attribute-name&quot;&gt;          className&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;text-gray-400 no-underline&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;        &amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;          Blackbird&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;        &amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;a&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;      &amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;div&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;    &amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;div&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;  )&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;};&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;以前はiframeのsrcに指定するurlは曲ページへのリンクと同じリンクを指定すればよかった
のですが、ここ数日の変更でiframeのsrcの指定はAPI専用のURLでなければならなく
なったようです。&lt;&#x2F;p&gt;
&lt;p&gt;この変更は既にアップロードされている曲には遡及していないようで、直近にアップ
ロードした曲のみに影響しています。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;SoundCloudEmbed_コンポーネントの変更&quot;&gt;SoundCloudEmbed コンポーネントの変更&lt;&#x2F;h2&gt;
&lt;p&gt;本来はSoundCloudでJavascriptのコードを取得すべきです。
このブログではMDXを使っている関係で取得したコードでは修正が必要なため、
&lt;code&gt;SoundCloudEmbed&lt;&#x2F;code&gt;というコンポーネントを作っていました。
この変更でShare Linkのみ指定していたSoundCloudEmbedは動かなくなりました。&lt;&#x2F;p&gt;
&lt;p&gt;仕方がないのでAPI用のURLを指定できようように修正しました。またタイトルの固定
でなく曲名を指定できるよう変更しています。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;typescript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;type&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; SoundCloudEmbedProps&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable z-object z-property&quot;&gt;  url&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-primitive&quot;&gt; string&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable z-object z-property&quot;&gt;  apiurl&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;?:&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-primitive&quot;&gt; string&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt; &#x2F;&#x2F; Optional API URL&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable z-object z-property&quot;&gt;  title&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;?:&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-primitive&quot;&gt; string&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;  &#x2F;&#x2F; Optional title&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;};&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-storage z-type&quot;&gt;export const&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; SoundCloudEmbed&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; React&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt;FC&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt;SoundCloudEmbedProps&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-typeparameters&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; (&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt;  url&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt;  apiurl&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt;  title&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-function z-arrow z-ts&quot;&gt; =&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;  &#x2F;&#x2F; SoundCloud の埋め込み URL 形式に変換&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;  &#x2F;&#x2F; If apiurl is provided, use it for the iframe source, otherwise use the url&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;  const&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt; sourceUrl&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt; apiurl&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; ||&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt; url&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;  const&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt; embedUrl&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; `https:&#x2F;&#x2F;w.soundcloud.com&#x2F;player&#x2F;?url=&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;${&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;encodeURIComponent&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt;sourceUrl&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt;&amp;amp;color=%23ff5500&amp;amp;auto_play=false&amp;amp;hide_related=false&amp;amp;show_comments=true&amp;amp;show_user=true&amp;amp;show_reposts=false&amp;amp;show_teaser=true`&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;  &#x2F;&#x2F; Prepare the display title&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;  const&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt; displayTitle&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt; title&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; ?&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; `Yostos - &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;${&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt;title&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;`&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; :&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;Yostos&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;  return&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; (&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;    &amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt;div className&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;w-full&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;      &amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt;iframe&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt;        width&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;100%&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt;        height&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;166&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt;        scrolling&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;no&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt;        frameBorder&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;no&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt;        allow&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;autoplay&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt;        src&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt;embedUrl&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;      &amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;&amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt;iframe&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;      &amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt;div className&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;text-[10px] text-gray-400 overflow-hidden whitespace-nowrap text-ellipsis font-light&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;        &amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt;a&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt;          href&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt;url&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt;          title&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt;displayTitle&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt;          target&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;_blank&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt;          rel&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;noopener noreferrer&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt;          className&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;text-gray-400 no-underline&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;        &amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;          {&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt;displayTitle&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;        &amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt;a&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;      &amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt;div&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;    &amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt;div&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;  )&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;};&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;API用URLだけ取得はできないので、結局埋め込み用のJavascriptのコードをSoundCloudから取得してURLを取り出して貼り付けることになります。
手間は貼り付けるより面倒なので、コンポーネントにした意味がないかもしれません。&lt;&#x2F;p&gt;
</content>
        <summary type="html">直近数日の内にSoundCloudはAPIの仕様を変更したようです。自作のTypeScriptコンポーネントがうまく機能しなくなったために対応しました。</summary>
        </entry><entry xml:lang="en">
        <title>MCP接続でClaudeにBlenderで3Dモデリングさせてみた</title>
        <published>2025-04-23T00:00:00+00:00</published>
        <updated>2025-04-23T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2025/04/blender-mcp/" type="text/html"/>
        <id>https://codedchords.dev/blog/2025/04/blender-mcp/</id>
        
            <content type="html">&lt;p&gt;Blender界隈でBlenderとClaudeをMCP接続してClaudeに3Dモデリングさせるというのが話題なので実際に試してみました。自然言語で依頼するとClaudeがモデリングツールを操作してくれます。&lt;&#x2F;p&gt;
&lt;details&gt;
&lt;summary&gt;Table of Contents&lt;&#x2F;summary&gt;
&lt;!-- toc --&gt;
&lt;&#x2F;details&gt;
&lt;h2 id=&quot;前提&quot;&gt;前提&lt;&#x2F;h2&gt;
&lt;p&gt;前提は次の通りです。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Blender 3.0以降&lt;&#x2F;li&gt;
&lt;li&gt;Python 3.10以降&lt;&#x2F;li&gt;
&lt;li&gt;uv package manager&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Blenderは無料の3Dモデリングツールなので、&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.blender.org&#x2F;&quot;&gt;公式サイト&lt;&#x2F;a&gt;からダウンロードしてインストールしておきます。&lt;&#x2F;p&gt;
&lt;p&gt;Pythonの環境は整えておきましょう。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;code&gt;uv&lt;&#x2F;code&gt;はPythonのパッケージなので、以下のようにインストールできます。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# Windowの場合&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;pip&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; install uv&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# Macの場合はHomebrewでも可&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;brew&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; install uv&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;Claudeの設定&quot;&gt;Claudeの設定&lt;&#x2F;h2&gt;
&lt;p&gt;使用するのは例によってClaude Desktopです。&lt;&#x2F;p&gt;
&lt;p&gt;いつものごとく、&lt;code&gt;claude_desktop_config.json&lt;&#x2F;code&gt;を編集します。
Claude DesktopからSettings &amp;gt; Developer &amp;gt; Edit Configで開けます。次のように
&lt;code&gt;blender-mcp&lt;&#x2F;code&gt;の設定を追加します。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;json&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;  &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;mcpServers&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;: {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;blender&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;: {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;      &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;command&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;uvx&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;      &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;args&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;: [&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;blender-mcp&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;  }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;Blender_MCP_サーバーのインストール&quot;&gt;Blender MCP サーバーのインストール&lt;&#x2F;h2&gt;
&lt;p&gt;Blender MCPの&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;blender-mcp.com&#x2F;download.html&quot;&gt;配布サイト&lt;&#x2F;a&gt;から最新版を
ダウンロードします。Zipでダウンロードされるので、展開しておきます。&lt;&#x2F;p&gt;
&lt;p&gt;Blenderを起動して、PreferencesからAdd-onsを開きます。&quot;Install Add-on from
File&quot;を選択して、先ほど展開したフォルダから&lt;code&gt;addon.py&lt;&#x2F;code&gt;を選びます。&lt;&#x2F;p&gt;
&lt;p&gt;インストールが完了すると、3D ViewのSidebarに&quot;Blender MCP&quot;のアイコンが追加さ
れます。
&quot;BlenderMCP&quot;のタブを開いて、&lt;code&gt;Poly Haven&lt;&#x2F;code&gt;のチェックボックスにチェックして
&lt;code&gt;start mcp server&lt;&#x2F;code&gt;をクリックします。&lt;&#x2F;p&gt;
&lt;p&gt;これで、Blender MCPが起動しています。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;Claudeにモデリングしてもらう&quot;&gt;Claudeにモデリングしてもらう&lt;&#x2F;h2&gt;
&lt;p&gt;Claudeにモデリングを依頼してみましょう。&lt;&#x2F;p&gt;
&lt;p&gt;Claudeには以下のように依頼しています。&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;BlenderでPoly HavenのHDRI、テクスチャ、そして岩や植生のようなモデルを使っ
て、ビーチの雰囲気を作り出してください。&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;実際にやっているところを見たほうが早いと思うので、動画にしました。&lt;&#x2F;p&gt;
&lt;div class=&quot;youtube-container&quot; style=&quot;position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden; max-width: 100%;&quot;&gt;
  &lt;iframe
    src=&quot;https:&#x2F;&#x2F;www.youtube-nocookie.com&#x2F;embed&#x2F;a6-DmRtty_8&quot;
    style=&quot;position: absolute; top: 0; left: 0; width: 100%; height: 100%;&quot;
    frameborder=&quot;0&quot;
    allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture&quot;
    allowfullscreen&gt;
  &lt;&#x2F;iframe&gt;
&lt;&#x2F;div&gt;
&lt;h2 id=&quot;まとめ&quot;&gt;まとめ&lt;&#x2F;h2&gt;
&lt;p&gt;今回はアセットを使っているとは言え「風景」だったので、3D画像として成立させる
モデリングは結構ハードルが高かったと思います。レンダリングした結果もちょっと
微妙でした。正直リアルな画像を得るだけであれば、Midjourneyなど画像生成AIを使
ったほうが良い結果になるでしょう。&lt;&#x2F;p&gt;
&lt;p&gt;ただ、シンプルなポリゴンモデルなら結構ちゃんとモデルを作ってくれます。
3Dモデルがあると、画角や視点を変えたシーンを何度も調整できるメリットがありま
す。&lt;&#x2F;p&gt;
&lt;p&gt;3Dモデリングはツールの使い方もハードルが高く、習得に時間がかかります。
AIを使って自然言語でモデリングできるようになれば結構革新的かなと思います。&lt;&#x2F;p&gt;
&lt;p&gt;MCPでいろいろ拡がっていきますね。&lt;&#x2F;p&gt;
</content>
        <summary type="html">Blender界隈でBlenderとClaudeをMCP接続してClaudeに3Dモデリングさせるというのが話題なので実際に試してみました。自然言語で依頼するとClaudeがモデリングツールを操作してくれます。</summary>
        </entry><entry xml:lang="en">
        <title>Apple Silicon時代のMacバックアップ最新戦略</title>
        <published>2025-04-18T00:00:00+00:00</published>
        <updated>2025-04-18T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2025/04/backup-strategy-for-mac/" type="text/html"/>
        <id>https://codedchords.dev/blog/2025/04/backup-strategy-for-mac/</id>
        
            <content type="html">&lt;h2 id=&quot;Macのバックアップ戦略&quot;&gt;Macのバックアップ戦略&lt;&#x2F;h2&gt;
&lt;p&gt;macOSはOS自体が&lt;strong&gt;TimeMachine&lt;&#x2F;strong&gt;という自動バックアップ機能を持っています。
以下のような特徴を持っています。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;特徴&lt;&#x2F;strong&gt;: macOSに標準搭載、独自形式でデータを保存&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;メリット&lt;&#x2F;strong&gt;: 設定が簡単、自動バックアップ、過去バージョンへのアクセス&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;デメリット&lt;&#x2F;strong&gt;: 独自形式のため通常のFinderからのアクセスが困難&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;アプローチ&lt;&#x2F;strong&gt;: 問題発生時はリカバリーからOSインストール後、Migration Assistantでデータ復元&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;iMacを使っていた時は使っていましたが、Macbookを使うようになってから
TimeMachineの使用を止めました。
理由は、バックアップ用にディスクが常にマウントされているとは限らないので
「自動バックアップ」の恩恵が相対的に薄く、加えて独自形式のためTimeMachineの
メカニズムでしかバップアップにアクセスできないためです。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;Apple_Silicon時代のバックアップの変化&quot;&gt;Apple Silicon時代のバックアップの変化&lt;&#x2F;h2&gt;
&lt;p&gt;TimeMachineを使用しない替わりに、長らく&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.shirt-pocket.com&#x2F;SuperDuper&#x2F;SuperDuperDescription.html&quot;&gt;SuperDuper&lt;&#x2F;a&gt;
や&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;bombich.com&#x2F;&quot;&gt;Carbon Copy Cloner&lt;&#x2F;a&gt;を使いディスクごと
完全なクローンを取っていました。
完全なクローンはブート可能なので、リカバリーの際にはクローンディスクから
macOSをブートしてリカバリーを行うことができました。&lt;&#x2F;p&gt;
&lt;p&gt;しかし、Apple Silicon搭載のMac（M1&#x2F;M2&#x2F;M3チップ）ではIntelが使われていた時代と
比較してシステムアーキテクチャが大きく変わりました。&lt;&#x2F;p&gt;
&lt;p&gt;主な変更点は次の通りです。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;OSが読み取り専用として保護されるようになった&lt;&#x2F;li&gt;
&lt;li&gt;リカバリー機能がより強化された（Recovery・Fallback Recoveryが内蔵）&lt;&#x2F;li&gt;
&lt;li&gt;外部ドライブからの起動に制限が追加された&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;バックアップ戦略も見直す必要が出てきました。
このためBootableな完全ディスククローンという戦略は以前ほど重要ではなくなりました。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;推奨バックアップ戦略&quot;&gt;推奨バックアップ戦略&lt;&#x2F;h2&gt;
&lt;p&gt;次のようなバックアップ戦略を変更することが必要です。&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;データ中心のバックアップ&lt;&#x2F;strong&gt;:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;OSではなく、ユーザーデータを確実に保護する&lt;&#x2F;li&gt;
&lt;li&gt;SuperDuperの場合は&lt;code&gt;Backup - User files&lt;&#x2F;code&gt;オプションが効率的&lt;&#x2F;li&gt;
&lt;li&gt;TimeMachineを使う場合は、同様にデータのバックアップに重点を置く&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;リカバリー戦略&lt;&#x2F;strong&gt;:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;問題発生時：
&lt;ol&gt;
&lt;li&gt;リカバリーモードから起動（⌘+Rキー）&lt;&#x2F;li&gt;
&lt;li&gt;OSをクリーンインストール&lt;&#x2F;li&gt;
&lt;li&gt;Migration Assistantを使ってバックアップからデータを復元&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;ストレージの選択&lt;&#x2F;strong&gt;:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;ユーザーデータのみをバックアップする場合、Mac本体と同程度の容量で十分&lt;&#x2F;li&gt;
&lt;li&gt;頻繁にアクセスする場合はSSD、コスト重視ならHDDを選択&lt;&#x2F;li&gt;
&lt;li&gt;NASを使用すれば、ネットワーク経由で自動バックアップも可能&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;h2 id=&quot;SuperDuperとTimeMachineの選択基準&quot;&gt;SuperDuperとTimeMachineの選択基準&lt;&#x2F;h2&gt;
&lt;p&gt;私自身はSuperDuperを使用していますが、有償のソフトウェアですしApple謹製の
TimeMachineを使いたい方もいると思います。
次のような観点で選択すればよいと思います。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;SuperDuperを選ぶ場合&lt;&#x2F;strong&gt;:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;バックアップから直接ファイルにアクセスしたい&lt;&#x2F;li&gt;
&lt;li&gt;標準ファイルシステムでの管理を好む&lt;&#x2F;li&gt;
&lt;li&gt;選択的なバックアップをしたい&lt;&#x2F;li&gt;
&lt;li&gt;バックアップスケールや方法を自分で調整したい&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;TimeMachineを選ぶ場合&lt;&#x2F;strong&gt;:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;設定の簡単さを重視&lt;&#x2F;li&gt;
&lt;li&gt;過去バージョンへの簡単なアクセスが必要&lt;&#x2F;li&gt;
&lt;li&gt;macOSに標準搭載の機能のみで完結させたい&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;まとめ&quot;&gt;まとめ&lt;&#x2F;h2&gt;
&lt;p&gt;Apple Silicon時代では、起動可能なバックアップよりも「確実にデータを保護し、
必要時に復元できる」戦略が重要です。OSはリカバリーモードから再インストールし
、大切なユーザーデータは確実にバックアップしておくことで、トラブル時も迅速に
復旧できます。&lt;&#x2F;p&gt;
&lt;p&gt;SuperDuperの最新ベータ版ではブータビリティの改善が進んでいますが、
現実的な運用としてはユーザーデータに焦点を当てた戦略が効率的です。&lt;&#x2F;p&gt;
&lt;p&gt;また、私はpCloudも使用しているため、
特に重要なファイルはpCloud上で作業するようにしています。
過去30日分のリビジョンが保存されますし、クラウドからいつでも取り出せます。&lt;&#x2F;p&gt;
&lt;p&gt;家庭用途では、
特にストレージコストを考慮すると、データ中心の定期的バックアップと
クラウドなどへの直近のデータの保管を併用すれば十分な保護が可能です。&lt;&#x2F;p&gt;
</content>
        <summary type="html">4月に入って日本語対応のApple IntelligenceをサポートしたmacOS Sequoia15.4、4月16日にはセキュリティアップデートのための15.1、その他Command LineToolsのアップデートなどが続いています。これらの更新の前には都度Macのバックアップと取っていますが、改めてMacのバックアップについて検討してみました。</summary>
        </entry><entry xml:lang="en">
        <title>国税庁の法人番号システムWeb-APIの検証</title>
        <published>2025-04-18T00:00:00+00:00</published>
        <updated>2025-04-18T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2025/04/company-info-api/" type="text/html"/>
        <id>https://codedchords.dev/blog/2025/04/company-info-api/</id>
        
            <content type="html">&lt;p&gt;仕事で企業を一意に特定するという要件があり、法人番号制度を利用するために
国税庁が提供する法人番号システムのWeb API
の検証のためのコードを作成してみました。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;法人番号制度とは&quot;&gt;法人番号制度とは&lt;&#x2F;h2&gt;
&lt;p&gt;法人番号制度は、2015年10月5日に発足しました。
この制度は、行政の効率化、国民の利便性の向上、および公平・公正な社会の実現を
目的として導入されました。法人には13桁の番号が指定され、商号や所在地といった
基本情報とともに国税庁の法人番号公表サイトで公開されています。&lt;&#x2F;p&gt;
&lt;p&gt;特に近年では、2023年10月から開始されたインボイス制度（適格請求書等保存方式）
との関連で、登録番号（T+法人番号等）を記載した適格請求書の発行が消費税の
仕入税額控除の要件となっているためシステムで扱うことも多くなっています。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;国税庁のWeb_APIについて&quot;&gt;国税庁のWeb APIについて&lt;&#x2F;h2&gt;
&lt;p&gt;国税庁が提供するAPIについては、&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.houjin-bangou.nta.go.jp&#x2F;webapi&#x2F;index.html&quot;&gt;法人番号システムのWep API&lt;&#x2F;a&gt;
のページに利用方法や申し込み方法がガイドされています。&lt;&#x2F;p&gt;
&lt;p&gt;利用には国税庁が振り出す「アプリケーションID」を取得する必要があります。
次の２つのアプリケーションIDがあります。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;インボイスWeb-APIを利用できるアプリケーションID&lt;&#x2F;li&gt;
&lt;li&gt;法人番号システムWeb-APIのみ利用できるアプリケーションID&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;前者は国税庁の承認を受ける必要がありますが、後者の法人番号システムのAPIにつ
いては申請だけでアプリケーションIDを振り出してくれます。ただし、申請してから
２週間から1ヶ月程度かかります。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;法人情報検索APIクライアント&quot;&gt;法人情報検索APIクライアント&lt;&#x2F;h2&gt;
&lt;p&gt;Typescriptで検証のためのコードを書いてみました。&lt;&#x2F;p&gt;
&lt;p&gt;法人名、または法人番号で検索できます。&lt;&#x2F;p&gt;
&lt;p&gt;実行すると、次のような標準出力にレスポンスをそのまま表示します。
(以下の例では、適当に折り返しています)&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;yostos&#x2F;get-company-info&quot;&gt;GitHubに公開&lt;&#x2F;a&gt;したので、ビルド方法や詳細な使い方はそちらをご覧ください。
検証用なのでエラー処理はいい加減です。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;╰─❯&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; npm start --  --type name 任天堂株式会社&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; company-info-api@1.0.0 start&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; node dist&#x2F;index.js --type name 任天堂株式会社&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;含まれている日本語：&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; 任天堂株式会社&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;日本語を含むか：&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language z-true&quot;&gt; true&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;&amp;lt;?&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;xml version&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;1.0&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; encoding&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;UTF-8&amp;quot;?&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;&amp;gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;corporations&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;&amp;gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;lastUpdateDate&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;2025-04-18&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;&amp;lt;&#x2F;lastUpdateDate&amp;gt;&amp;lt;count&amp;gt;1&amp;lt;&#x2F;count&amp;gt;&amp;lt;divideNumber&amp;gt;1&amp;lt;&#x2F;divideNumber&amp;gt;&amp;lt;di&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;videSize&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;1&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;&amp;lt;&#x2F;divideSize&amp;gt;&amp;lt;corporation&amp;gt;&amp;lt;sequenceNumber&amp;gt;1&amp;lt;&#x2F;sequenceNumber&amp;gt;&amp;lt;corpo&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;rateNumber&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;1130001011420&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;&amp;lt;&#x2F;corporateNumber&amp;gt;&amp;lt;process&amp;gt;01&amp;lt;&#x2F;process&amp;gt;&amp;lt;correct&amp;gt;1&amp;lt;&#x2F;c&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;orrect&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;&amp;gt;&amp;lt;updateDate&amp;gt;2018-07-18&amp;lt;&#x2F;updateDate&amp;gt;&amp;lt;changeDate&amp;gt;2015-10-05&amp;lt;&#x2F;changeDat&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;e&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;&amp;gt;&amp;lt;name&amp;gt;任天堂株式会社&amp;lt;&#x2F;name&amp;gt;&amp;lt;nameImageId&#x2F;&amp;gt;&amp;lt;kind&amp;gt;301&amp;lt;&#x2F;kind&amp;gt;&amp;lt;prefectureName&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;京都府&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;&amp;lt;&#x2F;prefectureName&amp;gt;&amp;lt;cityName&amp;gt;京都市南区&amp;lt;&#x2F;cityName&amp;gt;&amp;lt;streetNumber&amp;gt;上鳥羽鉾&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;立町１１番地１&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;&#x2F;streetNumber&amp;gt;&amp;lt;addressImageId&#x2F;&amp;gt;&amp;lt;prefectureCode&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;2&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;6&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;&#x2F;prefectureCode&amp;gt;&amp;lt;cityCod&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;e&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;107&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;&amp;lt;&#x2F;cityCode&amp;gt;&amp;lt;postCode&amp;gt;6018116&amp;lt;&#x2F;postCode&amp;gt;&amp;lt;addressOutside&#x2F;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;addressOutsideImageId&#x2F;&amp;gt;&amp;lt;closeDate&#x2F;&amp;gt;&amp;lt;closeCause&#x2F;&amp;gt;&amp;lt;successorCorporateNumber&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;changeCause&#x2F;&amp;gt;&amp;lt;assignmentDate&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;2015-10-&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;05&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;&#x2F;assignmentDate&amp;gt;&amp;lt;latest&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;1&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;&#x2F;latest&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;enName&#x2F;&amp;gt;&amp;lt;enPrefectureName&#x2F;&amp;gt;&amp;lt;enCityName&#x2F;&amp;gt;&amp;lt;enAddressOutside&#x2F;&amp;gt;&amp;lt;furigana&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;ニンテ&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;ンドウ&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;&amp;lt;&#x2F;furigana&amp;gt;&amp;lt;hihyoji&amp;gt;0&amp;lt;&#x2F;hihyoji&amp;gt;&amp;lt;&#x2F;corporation&amp;gt;&amp;lt;&#x2F;corporations&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;╰─❯&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; npm start -- --format csv --type name 任天堂株式会社&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; company-info-api@1.0.0 start&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; node dist&#x2F;index.js --format csv --type name 任天堂株式会社&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;含まれている日本語：&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; 任天堂株式会社&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;日本語を含むか：&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language z-true&quot;&gt; true&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;2025-04-18,1,1,1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;1,1130001011420,01,1,2018-07-18,2015-10-05,&amp;quot;任天堂株式会社&amp;quot;,,301,&amp;quot;京都府&amp;quot;,&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;京都市南区&amp;quot;,&amp;quot;上鳥羽鉾立町１１番地１&amp;quot;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;,26,107,6018116,,,,,,,2015-10-05,1,,,,,&amp;quot;ニンテンドウ&amp;quot;,0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;まとめ&quot;&gt;まとめ&lt;&#x2F;h2&gt;
&lt;p&gt;一応国の仕組みで、一意に法人を特定できるのいろいろ活用できて便利そうです。&lt;&#x2F;p&gt;
&lt;p&gt;私が社会人になりたての頃に同じような要件があり、
当時はこういったものがありませんでした。
そのため、名寄せしたり帝国データバンクの企業情報とぶつけたり苦労しました。
国がこんなものを提供してくれるなんて、いい時代だ。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;2025-04-20_追記&quot;&gt;2025-04-20 追記&lt;&#x2F;h2&gt;
&lt;p&gt;経済産業省も法人番号で検索できるAPIを公開していたので、対応しました。&lt;&#x2F;p&gt;
</content>
        <summary type="html">I had a requirement at work to uniquely identify companies, and to utilize the corporate number system, I created code to verify the Web API of the Corporate Number System provided by the National Tax Agency.</summary>
        </entry><entry xml:lang="en">
        <title>AWS Document MCP Serverを試す</title>
        <published>2025-04-16T00:00:00+00:00</published>
        <updated>2025-04-16T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2025/04/aws-mcp-servers/" type="text/html"/>
        <id>https://codedchords.dev/blog/2025/04/aws-mcp-servers/</id>
        
            <content type="html">&lt;h2 id=&quot;公式ブログ記事の概要&quot;&gt;公式ブログ記事の概要&lt;&#x2F;h2&gt;
&lt;p&gt;公開されたのは「&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;aws.amazon.com&#x2F;blogs&#x2F;machine-learning&#x2F;introducing-aws-mcp-servers-for-code-assistants-part-1&#x2F;&quot;&gt;Introducting AWS MCP Servers for code assistants(Part1)&lt;&#x2F;a&gt;
」という記事です。AWS MCPサーバーが紹介されています。&lt;&#x2F;p&gt;
&lt;p&gt;これらは、AWSのベストプラクティスを開発ワークフローに直接統合する特化型の
Model Context Protocol（MCP）サーバーのオープンソーススイートです。
このサーバー群は、AIアシスタントとAWSの深い知識を組み合わせ、開発時間を大幅に
短縮しながら、セキュリティコントロール、コスト最適化、AWS Well-Architectedの
ベストプラクティスを取り入れることを目的としているようです。&lt;&#x2F;p&gt;
&lt;p&gt;主要な特化型MCPサーバーとして以下が提供されています。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;コア：&lt;&#x2F;strong&gt; AIプロセスパイプライン機能を提供する基盤サーバー&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;AWS CDK：&lt;&#x2F;strong&gt; CDKの知識とベストプラクティス実装ツールを提供&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Amazon Bedrock Knowledge Bases：&lt;&#x2F;strong&gt; 企業の知識ベースへシームレスにアクセス&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Amazon Nova Canvas：&lt;&#x2F;strong&gt; Amazon Bedrockを通じた画像生成機能を提供&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;コスト分析：&lt;&#x2F;strong&gt; AWSサービスのコストを分析し、詳細なレポートを生成&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;具体的にどのようなMCPサーバーが提供されているかは、&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;awslabs&#x2F;mcp&#x2F;&quot;&gt;GitHub&lt;&#x2F;a&gt;で公開されています。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;AWS_Documentation_MCP_Serverを試す&quot;&gt;AWS Documentation MCP Serverを試す&lt;&#x2F;h2&gt;
&lt;p&gt;手っ取り早そうなので、AWS Documentation MCP Serverを試してみました。&lt;&#x2F;p&gt;
&lt;p&gt;このAPIでは、AWSの公式ドキュメントとベストプラクティスにアクセスしたり、
ドキュメントをMarkdown形式にコンバートできるようです。&lt;&#x2F;p&gt;
&lt;p&gt;AWSの提供する設定サンプルを見ると、Astral社が開発したPython向けのツール管理
コマンド &lt;code&gt;uv&lt;&#x2F;code&gt;を使用しているようです。まず、&lt;code&gt;uv&lt;&#x2F;code&gt;をインストールします。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# 公式インストーラー&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; curl -LsSf https:&#x2F;&#x2F;astral.sh&#x2F;uv&#x2F;install.sh&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; |&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; sh&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# MacでHomebrewでインストールする場合&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; brew install uv&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;デスクトップ版Claudeからアクセスする想定で設定します。
設定メニュー内の開発者メニューから、&lt;code&gt;claude_desktop_config.json&lt;&#x2F;code&gt;を開いて編集
します。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;json&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;  &amp;quot;mcpServers&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;: &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;inkdrop&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;: {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;      &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;command&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;&#x2F;Users&#x2F;hogehoge&#x2F;bin&#x2F;inkdrop-mcp&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;      &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;args&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;: [],&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;      &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;env&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;: {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;        &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;INKDROP_LOCAL_SERVER_URL&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;http:&#x2F;&#x2F;localhost:19840&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;        &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;INKDROP_LOCAL_USERNAME&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;hogehoge&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;        &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;INKDROP_LOCAL_PASSWORD&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;hagehage&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;      }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    },&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;claude_code&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;: {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;      &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;command&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;&#x2F;Users&#x2F;hogehoge&#x2F;bin&#x2F;claude-code-mcp&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;      &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;args&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;: [],&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;      &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;env&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;: {}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    },&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;aws_document&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;: {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;      &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;command&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;&#x2F;opt&#x2F;homebrew&#x2F;bin&#x2F;uvx&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;      &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;args&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;: [&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;awslabs.aws-documentation-mcp-server@latest&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;],&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;      &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;env&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;: {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;        &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;FASTMCP_LOG_LEVEL&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;ERROR&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;      },&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;      &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;disabled&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language z-json&quot;&gt; false&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;      &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;autoApprove&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;: []&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;  }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;この例では、Inkdrop, Claude CodeもMCPサーバーとして登録していますが、
必要なのは最後の例だけです。なお、上記はHomebrewでインストールした場合です。
公式インストーラーを使用した場合、パスが異なりますから注意してください。&lt;&#x2F;p&gt;
&lt;p&gt;上記の設定後、Claudeの再起動が必要です。&lt;&#x2F;p&gt;
&lt;p&gt;早速確認してみましょう。&lt;&#x2F;p&gt;
&lt;p&gt;デスクトップ版Claudeから、
「aws_documentから東京リージョンでBedrockにて
利用可能なモデルの一覧を作成してください」と依頼してみました。&lt;&#x2F;p&gt;
&lt;p&gt;以下のように、MCP使用の許可を求めながら処理を行っています。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;お手伝いします。AWS Bedrockで現在利用可能なモデルの一覧を作成するために、AWS&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;公式ドキュメントから情報を検索しましょう。&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;モデル情報の詳細を確認するために、関連するAWSドキュメントページを読み取りま&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;しょう。&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;モデルの詳細情報を取得するために、利用可能なモデルの一覧に関するドキュメント&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;を検索します：&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;サポートされているモデルのリストを確認するために、もう一つのドキュメントを読&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;み取ります：&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;基本的なモデル一覧を確認するドキュメントを検索します：&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;もう少し具体的に検索します：&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Converseで利用可能なモデルを確認します：&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;モデルのリージョン対応を確認するために、追加のドキュメントを読み取ります：&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;これで十分な情報が得られました。収集した情報に基づいて、AWS Bedrockで現在利&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;用可能なモデルの一覧を作成します。&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;AWS Bedrockで現在利用可能なモデルの一覧をまとめました。&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;結果、完成したドキュメント&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-1-1&quot;&gt;&lt;a href=&quot;#fn-1&quot;&gt;1&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;は、AWSのSolution Architectが作成したような丁寧な回答でした。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;まとめ&quot;&gt;まとめ&lt;&#x2F;h2&gt;
&lt;p&gt;今回はAWS Documentation MCP Serverをデスクトップ版Claudeからアクセスすること
を試してみました。&lt;&#x2F;p&gt;
&lt;p&gt;最近のClaudeはWeb検索をやってくれるので、MCPサーバーを使用
しなくても同様の結果は得ることができそうです。
しかし、ソースを限定して「公式ドキュメントから」と指定できるのは安心です。&lt;&#x2F;p&gt;
&lt;p&gt;Core MCP Serverというものが提供されており、一連のMCPサーバーのオーケストレー
ションを行うようです。もしかすると今回の使い方は想定と違うのかもしれません。&lt;&#x2F;p&gt;
&lt;p&gt;AWS Diagram MCP ServerはAWSダイアグラムを生成してくれるようなのです。
実際の環境からその各種ダイアグラムをGraphVizで描いてくれるなら、
取っても便利そうです。&lt;&#x2F;p&gt;
&lt;p&gt;やっぱり、今MCPは熱いですね。&lt;&#x2F;p&gt;
&lt;section class=&quot;footnotes&quot;&gt;
&lt;ol class=&quot;footnotes-list&quot;&gt;
&lt;li id=&quot;fn-1&quot;&gt;
&lt;p&gt;Claude Artifactsで生成されたドキュメント（一時URLのため現在はアクセス不可） &lt;a href=&quot;#fr-1-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;&#x2F;section&gt;
</content>
        <summary type="html">4月1日のAWS公式ブログで、AWS MCP Serversの記事が掲載されました。早速AWS公式ドキュメントをMCPサーバーとして利用できるAWS Documentation MCP Serverを試してみました。</summary>
        </entry><entry xml:lang="en">
        <title>プロンプトエンジニアリング技法の総合ガイド</title>
        <published>2025-04-15T00:00:00+00:00</published>
        <updated>2025-04-15T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2025/04/prompt-engineering/" type="text/html"/>
        <id>https://codedchords.dev/blog/2025/04/prompt-engineering/</id>
        
            <content type="html">&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.aibase.com&#x2F;ja&#x2F;news&#x2F;17051&quot;&gt;AI Baseの記事&lt;&#x2F;a&gt;でこのホワイトペーパーが紹介されていたので、
原文を読んでみました。&lt;&#x2F;p&gt;
&lt;p&gt;この論文は、大規模言語モデル(LLM)向けのプロンプトエンジニアリング手法を包括的に解説しています。
データサイエンティストでなくても効果的なプロンプトを作成できること、
LLMの設定（温度、top-K、top-P、トークン制限など）がプロンプトの効果に大きく影響することなどが
強調されています。&lt;&#x2F;p&gt;
&lt;p&gt;プロンプトテクニックとして整理されており、生成AIと付きあう前提のナレッジとし
て有用だと思うのでまとめておきます。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;出典情報&quot;&gt;出典情報&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;論文タイトル：「Prompt Engineering」（※掲載サイトgptaiflow.techは閉鎖済み）&lt;&#x2F;li&gt;
&lt;li&gt;著者：Lee Boonstra（他複数の貢献者）&lt;&#x2F;li&gt;
&lt;li&gt;発行元：Google&lt;&#x2F;li&gt;
&lt;li&gt;発行日：2024年11月&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;主要なプロンプト技法&quot;&gt;主要なプロンプト技法&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;1._ゼロショットプロンプト_(Zero-shot_Prompting)&quot;&gt;1. ゼロショットプロンプト (Zero-shot Prompting)&lt;&#x2F;h3&gt;
&lt;p&gt;例を示さず、直接タスクを指示する基本的な手法です。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;映画レビューをPOSITIVE、NEUTRAL、NEGATIVEに分類してください。&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;レビュー：&amp;quot;Her&amp;quot;は人工知能の進化が人類に与える影響を描いた傑作です。&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;2._ワンショット&#x2F;フューショットプロンプト_(One-shot_&amp;amp;_Few-shot_Prompting)&quot;&gt;2. ワンショット&#x2F;フューショットプロンプト (One-shot &amp;amp; Few-shot Prompting)&lt;&#x2F;h3&gt;
&lt;p&gt;1つまたは複数の例を示すことで、モデルに期待する出力パターンを教える手法です。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;顧客のピザ注文をJSONに解析してください。&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;例: &amp;quot;チーズとペパロニのピザを注文したい&amp;quot; →&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;json&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;  &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;size&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;small&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;  &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;ingredients&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;: [&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;cheese&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;pepperoni&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;注文: &amp;quot;モッツァレラとバジルのピザをLサイズで&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;3._システムプロンプト_(System_Prompting)&quot;&gt;3. システムプロンプト (System Prompting)&lt;&#x2F;h3&gt;
&lt;p&gt;モデルの全体的な目的や動作を設定する手法です。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;映画レビューを分類し、結果をJSONフォーマットで返してください。&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;4._ロールプロンプト_(Role_Prompting)&quot;&gt;4. ロールプロンプト (Role Prompting)&lt;&#x2F;h3&gt;
&lt;p&gt;モデルに特定の役割を与えて、回答させる手法です。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;旅行ガイドとして振る舞ってください。アムステルダムで訪れるべき3つの場所をリ&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;ストアップしてください。&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;5._文脈プロンプト_(Contextual_Prompting)&quot;&gt;5. 文脈プロンプト (Contextual Prompting)&lt;&#x2F;h3&gt;
&lt;p&gt;関連する背景情報を提供して理解を深める手法です。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;文脈：あなたは80年代のレトロゲームについてのブログを書いています。&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;そのブログ用の記事のトピックを3つ提案してください。&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;6._ステップバックプロンプト_(Step-back_Prompting)&quot;&gt;6. ステップバックプロンプト (Step-back Prompting)&lt;&#x2F;h3&gt;
&lt;p&gt;特定のタスクを実行させる前に、より一般的な質問を考慮させる手法です。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;FPSゲームのレベル設計で重要な要素は何ですか？&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;[回答を受け取った後]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;その要素を考慮したFPSゲームのレベルの設計案を作成してください。&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;7._思考連鎖_(Chain_of_Thought,_CoT)&quot;&gt;7. 思考連鎖 (Chain of Thought, CoT)&lt;&#x2F;h3&gt;
&lt;p&gt;中間推論ステップを生成して最終回答の精度を向上させる手法です。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;3歳の時、パートナーは私の3倍の年齢でした。現在私は20歳です。&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;パートナーの年齢は？&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;ステップバイステップで考えましょう。&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;8._自己一貫性_(Self-consistency)&quot;&gt;8. 自己一貫性 (Self-consistency)&lt;&#x2F;h3&gt;
&lt;p&gt;複数の推論経路を生成し、最も一貫した回答を選択する手法です。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;このメールは重要ですか？内容を分析して結論を導き出してください。&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;[同じプロンプトを複数回実行し、最も多く出現する回答を採用]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;9._思考木_(Tree_of_Thoughts,_ToT)&quot;&gt;9. 思考木 (Tree of Thoughts, ToT)&lt;&#x2F;h3&gt;
&lt;p&gt;複数の推論パスを探索できるよう、思考連鎖を拡張した手法です。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;[問題解決において複数のアプローチを同時に検討させる手法]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;10._ReAct（理由付けと行動）_(ReAct:_Reason_&amp;amp;_Act)&quot;&gt;10. ReAct（理由付けと行動） (ReAct: Reason &amp;amp; Act)&lt;&#x2F;h3&gt;
&lt;p&gt;外部ツールと組み合わせて推論と行動を交互に行う手法です。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;メタリカのバンドメンバーには合計何人の子供がいますか？&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;[検索ツールを使って各メンバーについて調査し、結果を合計]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;11._自動プロンプトエンジニアリング_(Automatic_Prompt_Engineering)&quot;&gt;11. 自動プロンプトエンジニアリング (Automatic Prompt Engineering)&lt;&#x2F;h3&gt;
&lt;p&gt;LLMを使って他のLLM用のプロンプトを生成・評価・改善する手法です。LLMでなくMidjourney向けのプロンプトをClaudeに生成させるなど私はよく使います。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Tシャツを注文する10種類の表現を生成してください。&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;12._コードプロンプティング_(Code_Prompting)&quot;&gt;12. コードプロンプティング (Code Prompting)&lt;&#x2F;h3&gt;
&lt;p&gt;コード関連のタスクに特化したプロンプト技法については、次の4つのサブカテゴリに分けることができます。&lt;&#x2F;p&gt;
&lt;h4 id=&quot;a._コードを書くためのプロンプト_(Prompts_for_writing_code)&quot;&gt;a. コードを書くためのプロンプト (Prompts for writing code)&lt;&#x2F;h4&gt;
&lt;p&gt;特定のタスクのコードを生成するプロンプトです。実行環境、入出力形式、エラー処理などの要件を明示するとより効果的です。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;特定のフォルダ内のすべてのファイル名の先頭に&amp;quot;draft&amp;quot;という文字列を追加する&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Bashスクリプトを書いてください。&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h4 id=&quot;b._コードを説明するためのプロンプト_(Prompts_for_explaining_code)&quot;&gt;b. コードを説明するためのプロンプト (Prompts for explaining code)&lt;&#x2F;h4&gt;
&lt;p&gt;コードの機能、構造、ロジックを人間が理解しやすく解説させるプロンプトです。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;以下のBashコードを説明してください：&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;#!&#x2F;bin&#x2F;bash&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;echo &amp;quot;フォルダ名を入力してください：&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;read folder_name&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;...&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h4 id=&quot;c._コードを翻訳するためのプロンプト_(Prompts_for_translating_code)&quot;&gt;c. コードを翻訳するためのプロンプト (Prompts for translating code)&lt;&#x2F;h4&gt;
&lt;p&gt;ある言語で書かれたコードを別の言語に変換するプロンプトです。元のコードの機能を担保するよう強調すると良い結果になるようです。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;以下のBashスクリプトをPythonコードに変換してください：&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;#!&#x2F;bin&#x2F;bash&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;echo &amp;quot;フォルダ名を入力してください：&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;...&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h4 id=&quot;d._コードをデバッグ・レビューするためのプロンプト_(Prompts_for_debugging_and_reviewing_code)&quot;&gt;d. コードをデバッグ・レビューするためのプロンプト (Prompts for debugging and reviewing code)&lt;&#x2F;h4&gt;
&lt;p&gt;バグの特定、修正、およびコード品質の向上提案を求めるプロンプトです。エラーメッセージやスタックトレースを含めると効果的です。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;以下のPythonコードにはエラーがあります：&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;エラーを修正し、コード全体を改善してください。&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;python&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;folder_name&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-builtin z-python&quot;&gt; input&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;フォルダ名を入力：&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;prefix&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-builtin z-python&quot;&gt; input&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;ファイル名の先頭に追加する文字列：&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;text&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt; toUpperCase&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;prefix&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;...&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;ベストプラクティス&quot;&gt;ベストプラクティス&lt;&#x2F;h2&gt;
&lt;p&gt;次に個別のテクニックというよりプロンプト全般でのベストプラクティスです。&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;例を提供する&lt;&#x2F;strong&gt;：期待する出力の例を示すことで精度を向上&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;シンプルでわかりやすいプロンプトを設計&lt;&#x2F;strong&gt;：明確な言語を使用&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;出力形式を明確に指定&lt;&#x2F;strong&gt;：「3段落のブログ記事を生成」など具体的に&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;制約よりも指示を優先&lt;&#x2F;strong&gt;：否定形より肯定形の表現が効果的&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;JSONなどの構造化出力を使用&lt;&#x2F;strong&gt;：データ抽出・分類タスクに有効&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;トークン長を制御&lt;&#x2F;strong&gt;：設定またはプロンプト内で指定&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;プロンプトに変数を使用&lt;&#x2F;strong&gt;：再利用可能で動的なプロンプト作成&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;入力形式やスタイルを実験&lt;&#x2F;strong&gt;：質問、声明、指示など&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;分類タスクでは異なるクラスの例をミックス&lt;&#x2F;strong&gt;：バイアス防止のため&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;モデルの更新に適応&lt;&#x2F;strong&gt;：新バージョンでプロンプトを再テスト&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;プロンプトの試行を詳細に記録&lt;&#x2F;strong&gt;：モデル、設定、プロンプト、出力を文書化&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;一旦JSON経由にするなど経験としては効果的なので、私はよく使います。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;まとめ&quot;&gt;まとめ&lt;&#x2F;h2&gt;
&lt;p&gt;この論文ではプロンプトエンジニアリングの様々な技法を紹介しています。ゼロショットから高度な推論技法（思考連鎖、自己一貫性、思考木）、そしてコード生成・操作のためのプロンプティングまで、幅広い手法が解説されています。&lt;&#x2F;p&gt;
&lt;p&gt;プロンプトエンジニアリングは反復的なプロセスであり、モデルのパフォーマンスに基づいてプロンプトを継続的に改良することが重要です。また、表形式でプロンプト試行を記録し、異なるモデルバージョンや設定での結果を比較することが推奨されています。&lt;&#x2F;p&gt;
&lt;p&gt;コードプロンプティングの分野では、生成、説明、翻訳、デバッグという開発サイクル全体をカバーする技法が提示されており、開発効率の向上に貢献します。特にデバッグとレビューの機能は、単なるバグ修正だけでなく、コード品質の全体的な向上につながる可能性を持っています。&lt;&#x2F;p&gt;
</content>
        <summary type="html">最近GoogleのLee Boonstrが最近発表した69ページのプロンプトエンジニアリングに関するホワイトペーパーを読みました。このホワイトペーパーでは大規模言語モデル（LLM）との対話を最適化するための包括的なガイドを提供されています。これまでなんとなく経験や勘で作っていたプロンプトを、テクニックとして整理することができます。</summary>
        </entry><entry xml:lang="en">
        <title>Anthropic announced Claude Max Plan</title>
        <published>2025-04-10T00:00:00+00:00</published>
        <updated>2025-04-10T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2025/04/anthropic-max-plan/" type="text/html"/>
        <id>https://codedchords.dev/blog/2025/04/anthropic-max-plan/</id>
        
            <content type="html">&lt;p&gt;今朝Anthropicから新しいプランの案内する次のようなメールが来ていました。&lt;&#x2F;p&gt;
&lt;blockquote&gt;
  We’ve heard your request for more access to Claude so you can maintain
  momentum on your most demanding projects with less disruption. Today, we’re
  introducing the new Max plan that delivers exactly that. With the Max plan,
  you can get:
  &lt;ul&gt;
    &lt;li&gt;
      &lt;strong&gt;Substantially more usage&lt;&#x2F;strong&gt; to work with Claude
    &lt;&#x2F;li&gt;
    &lt;li&gt;
      &lt;strong&gt;5x more usage&lt;&#x2F;strong&gt; ($100&#x2F;month) or 20x more usage ($200&#x2F;month)
      than Pro
    &lt;&#x2F;li&gt;
    &lt;li&gt;
      &lt;strong&gt;Be among the first&lt;&#x2F;strong&gt; to try the most advanced Claude
      capabilities
    &lt;&#x2F;li&gt;
    &lt;li&gt;
      &lt;strong&gt;Flexibility&lt;&#x2F;strong&gt; to scale as your needs grow
    &lt;&#x2F;li&gt;
  &lt;&#x2F;ul&gt;
  Your best ideas deserve more room to grow. We’re excited to see the new
  possibilities the Max plan can unlock for you.
  &lt;footer&gt;
    &lt;cite&gt;
      &amp;mdash;Anthropic&quot;Introducing the Max plan — get more Claude usage than
      ever before&quot;
    &lt;&#x2F;cite&gt;
  &lt;&#x2F;footer&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;新しい&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.anthropic.com&#x2F;pricing&quot;&gt;Claude Maxプラン&lt;&#x2F;a&gt;の案内です
。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;Claude_Max_プランの概要&quot;&gt;Claude Max プランの概要&lt;&#x2F;h2&gt;
&lt;p&gt;Claude MaxプランはClaude Proプランの上位サブスクリプションとして、業務用途や超
ヘビーユーザーを対象として用意されたものです。&lt;&#x2F;p&gt;
&lt;p&gt;強化されるポイントは以下のような点です。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;1._利用上限の拡大&quot;&gt;1. &lt;strong&gt;利用上限の拡大&lt;&#x2F;strong&gt;&lt;&#x2F;h3&gt;
&lt;p&gt;Claude Maxでは、既存の「Claude Pro」プラン（月額20ドル）と比較して以下のよう
な利用上限の大幅な拡大が行われます。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;月額100ドルプラン&lt;&#x2F;strong&gt;: Proプランの5倍の使用量。&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;月額200ドルプラン&lt;&#x2F;strong&gt;: Proプランの20倍の使用量。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;これにより、長文の処理や複雑なタスク、大量のリクエストを頻繁に行う用途でも、
中断を気にすることなく作業を進行可能です。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;2._新機能への優先アクセス&quot;&gt;2. &lt;strong&gt;新機能への優先アクセス&lt;&#x2F;strong&gt;&lt;&#x2F;h3&gt;
&lt;p&gt;「Claude Max」加入者は、Anthropicの最新AIモデルや新機能に優先的にアクセスで
きる特典が付与されます。これには以下が含まれます。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;新モデルへの早期アクセス。&lt;&#x2F;li&gt;
&lt;li&gt;新機能のテスト権限。&lt;&#x2F;li&gt;
&lt;li&gt;開発中の高度な機能（例: 音声モードなど）の事前利用。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;3._コンテキストウィンドウの最大化&quot;&gt;3. &lt;strong&gt;コンテキストウィンドウの最大化&lt;&#x2F;strong&gt;&lt;&#x2F;h3&gt;
&lt;p&gt;このプランでは、モデルが一度に処理できるテキスト量（コンテキストウィンドウ）
が従来モデルよりもさらに拡充されています。長文や複雑な文脈に依存する作業が効
率的に行えます。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;4._混雑時の優先アクセス&quot;&gt;4. &lt;strong&gt;混雑時の優先アクセス&lt;&#x2F;strong&gt;&lt;&#x2F;h3&gt;
&lt;p&gt;「Claude Max」プランのユーザーは、混雑した時間帯でも優先的にアクセスできるた
め、業務上の遅延を回避できます。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;Claude_Maxプランの評価&quot;&gt;Claude Maxプランの評価&lt;&#x2F;h2&gt;
&lt;p&gt;Claude Maxプランは、OpenAIのChatGPT Pro（月額200ドル）やその他の競合サービスへの対
抗策として設計されており、AIアシスタントの活用をさらに拡大したい次のようなユーザーに
とって魅力的な選択肢となっています。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;作業を改良し完成させるために長時間の会話が必要&lt;&#x2F;li&gt;
&lt;li&gt;定期的に大量の文書や複雑なデータを扱う&lt;&#x2F;li&gt;
&lt;li&gt;現在の使用制限を待てない締め切りがある&lt;&#x2F;li&gt;
&lt;li&gt;日常のさまざまなタスクでClaudeに頼っている&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;私自身もClaude Proを使っていますが、複雑なこと検討では上限に達してしまい一時
的に中断しなければならないシーンは確かにあります。ただ、次のような観点から
このClaude Maxプランは利用しないと思います。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;使用制限を受けてしまうことはあるが、緊急性はそれほど高くないため多くの場合
は一時的に作業を中断できる。緊急性が高い場合はClade Codeなどの代替手段がある&lt;&#x2F;li&gt;
&lt;li&gt;大量情報を使った処理はチャットウィンドウで行うより、Claude CodeやMCP経由
でClaude Desktopで処理したほうが効率的&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;つまり技術者であれば、Claude Proプランと有償のAPI経由でClaudeを利用したほう経済的
、かつ効率的です。非技術者でヘビーにClaudeを活用し高い緊急度のニーズがある場
合はClaude Maxプランが向いていると思います。&lt;&#x2F;p&gt;
</content>
        <summary type="html">Anthropic announced Claude Max Plan</summary>
        </entry><entry xml:lang="en">
        <title>OpenAI will support MCP</title>
        <published>2025-04-08T00:00:00+00:00</published>
        <updated>2025-04-08T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2025/04/openai-mcp-support/" type="text/html"/>
        <id>https://codedchords.dev/blog/2025/04/openai-mcp-support/</id>
        
            <content type="html">&lt;h2 id=&quot;AltmanのツイートによるMCP対応のアナウンス&quot;&gt;AltmanのツイートによるMCP対応のアナウンス&lt;&#x2F;h2&gt;
&lt;p&gt;以下が3月末のAltmanのツイート(X)です。&lt;&#x2F;p&gt;
&lt;blockquote cite=&quot;https:&#x2F;&#x2F;x.com&#x2F;sama&#x2F;status&#x2F;1904957253456941061&quot;&gt;
  people love MCP and we are excited to add support across our products.
  available today in the agents SDK and support for chatgpt desktop app +
  responses api coming soon!
  &lt;footer&gt;
    &lt;cite&gt;
      &lt;a href=&quot;https:&#x2F;&#x2F;x.com&#x2F;sama&#x2F;status&#x2F;1904957253456941061&quot;&gt;
        &amp;mdash; Sam Altman (March 26, 2025)
      &lt;&#x2F;a&gt;
    &lt;&#x2F;cite&gt;
  &lt;&#x2F;footer&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;MCP(Model Context Protocol)はAnthropicが提唱しているフレームワーク
ですが、上記は&lt;strong&gt;OpenAIもMCPをサポートする&lt;&#x2F;strong&gt;というアナウンスです。&lt;&#x2F;p&gt;
&lt;p&gt;とても重要な意味を持つアナウンスだと思います。
AnthropicはOpenAIの強力なライバルで競合関係にあります。
デファクト・スタンダードが無い現状では対応する規格を提唱できたはずですが、
それをせずMCPサポートに舵を切ったのは素晴らしい経営判断だと思います。&lt;&#x2F;p&gt;
&lt;p&gt;これにより、MCPがほぼ業界のデファクト・スタンダードになると思います。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;MCP(Model_Context_Protocol)とは&quot;&gt;MCP(Model Context Protocol)とは&lt;&#x2F;h2&gt;
&lt;p&gt;以前いくつか記事を書いていますが、ちゃんとMCPの説明を書いていませんでした。&lt;&#x2F;p&gt;
&lt;p&gt;Model Context Protocol (MCP)は、大規模言語モデル(LLM)に対する指示を構造化す
るためのフレームワークです。&lt;&#x2F;p&gt;
&lt;p&gt;次のような要素から構成されています。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Model（モデル）&lt;&#x2F;strong&gt; - AIモデルがどのように自分自身を認識し、振る舞うべきかを定義する&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Context（コンテキスト）&lt;&#x2F;strong&gt; - モデルが参照すべき情報や知識を提供する&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Protocol（プロトコル）&lt;&#x2F;strong&gt; - モデルの動作や応答方法のルールを設定する&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;&lt;a href=&quot;&#x2F;articles&#x2F;2025&#x2F;03&#x2F;28&#x2F;claude-integration-with-inkdrop&quot;&gt;以前の記事&lt;&#x2F;a&gt;では、
&lt;strong&gt;Context&lt;&#x2F;strong&gt;を使って独自のナレッジ(Inkdrop)をClaudeに追加するということをやっただけですが、
Claude活用の可能性が途端に広がりものすごい効果を体感できました。これまでも
Contextの部分にだけ限るとRAG (Retrieval-Augmented Generation)という手法があ
りましたが、こんなに簡単にはできなかったと思います。&lt;&#x2F;p&gt;
&lt;p&gt;MCPではContextだけでなく、Protocolを通じて行動規範の設定や、Modelを通じた企業の
ブランドトーンに合わせた応答スタイルなどに応用できます。&lt;&#x2F;p&gt;
&lt;p&gt;MCPにより、明確に分離された要素(Model&#x2F;Context&#x2F;Protocol)に整理され、
単なるプロンプトエンジニアリングを超えて体系化されたアプローチで
AIの応答をより予測可能で一貫性のあるものにすることが可能となりました。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;MCPがデファクト・スタンダードになると&quot;&gt;MCPがデファクト・スタンダードになると&lt;&#x2F;h2&gt;
&lt;p&gt;MCPがデファクト・スタンダードとなればAI関連ツール間の標準化された通信パターンを
提供していることになるでしょう。&lt;&#x2F;p&gt;
&lt;p&gt;この事実を踏まえるとClaudeデスクトップがClaude Codeをナレッジソースとして扱えるように、次のよう
なことが可能になるかもしれません。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;ChatGPT-Claudeクロス連携&lt;&#x2F;strong&gt;: ChatGPTの回答をClaudeが評価するようなAIシステム間の直接的な情報交換や連携&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;AIオーケストレーション&lt;&#x2F;strong&gt;: 複数の生成AIがそれぞれ
の強みを生かした連携し、結果を統合するようなワークフロー構築の可能性。例え
ば、データ解析はChatGPT、文章生成はClaude、検証はGeminiなどの役割分担するイ
メージ。&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;統一ナレッジアクセス&lt;&#x2F;strong&gt;: マーケットにMCP準拠した多数のナレッジベースが
登場し、簡単に新しいナレッジを自社のAIに追加できる可能性&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;いずれも現時点で実現できるかどうか検証が必要というレベルです。
AIオーケストレーションなどは追加の標準化やツールが必要でしょう。
また、技術的に標準化の方向で協力できたからと言って、今後ビジネス上の判断で
その適用範囲が制限される可能性はあります。&lt;&#x2F;p&gt;
&lt;p&gt;しかし、このような動きを見ていると、加速度的にAIの世界が拡がっていくのを実感しています。楽しみです。&lt;&#x2F;p&gt;
</content>
        <summary type="html">MCPをサポートしたAnthropicのClaudeで試しましたが、その可能性に驚きました。3月末にはOpenAIもMCP対応を表明していたので楽しみです。</summary>
        </entry><entry xml:lang="en">
        <title>Open Graph Protocol対応</title>
        <published>2025-04-07T00:00:00+00:00</published>
        <updated>2025-04-07T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2025/04/open-graph-protocol/" type="text/html"/>
        <id>https://codedchords.dev/blog/2025/04/open-graph-protocol/</id>
        
            <content type="html">&lt;h2 id=&quot;Open_Graph_Protocolとは&quot;&gt;Open Graph Protocolとは&lt;&#x2F;h2&gt;
&lt;p&gt;Open Graph Protocol(OGPとも呼ばれます)は、Webページの内容をSNSなどで共有する際に、正確な情報を
表示するための仕組みです。
2010年にFacebookが開発し、現在は多くのWebサイトで採用されています。&lt;&#x2F;p&gt;
&lt;p&gt;OGPでは、HTMLのhead内にmeta要素を配置し、「og:」というプレフィックスを持つプ
ロパティを使用して、ページの様々な情報を定義します。
主な要素としては、ページのタイトル、ページの説明、サムネイル画像のURL、
正規URLなどがあります。&lt;&#x2F;p&gt;
&lt;p&gt;これらの情報を適切に設定することで、FacebookやTwitter、LINEなどのSNSでリンクがシェアされた際に、
単なるURLではなく、タイトル、説明文、画像を含む魅力的なプレビューカードが表示されます。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;このブログの対応&quot;&gt;このブログの対応&lt;&#x2F;h2&gt;
&lt;p&gt;記事ページのメタ情報を管理している&lt;code&gt;lib&#x2F;metadata.ts&lt;&#x2F;code&gt;を修正してOGPに対応するヘッダを
追加するロジックを入れました。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-storage z-type&quot;&gt;export function&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; generateArticleMetadata&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt;  article&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; Article&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; &amp;amp;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; {&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-object z-property&quot;&gt; path&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;?:&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-primitive&quot;&gt; string&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; },&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; Metadata&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;  &#x2F;&#x2F; pathがある場合はURLを生成&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;  const&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-constant z-js&quot;&gt; url&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; article&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-property z-js&quot;&gt;path&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;    ?&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; generateArticleUrl&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(article&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-property z-js&quot;&gt;date&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; article&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-property z-js z-source&quot;&gt;path)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;    :&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language z-undefined z-js&quot;&gt; undefined&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;  &#x2F;&#x2F; OGP画像のURL&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;  const&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-constant z-js&quot;&gt; ogImageUrl&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; generateOgImageUrl&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;()&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;  return&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    title&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; article&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-property z-js&quot;&gt;title&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    description&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; article&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-property z-js&quot;&gt;description&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    authors&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; name&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; article&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-property z-js&quot;&gt;author&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; ||&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; siteConfig&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-property z-js&quot;&gt;author&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; }&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;]&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;    &#x2F;&#x2F; OGP設定&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    openGraph&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;      siteName&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; siteConfig&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-property z-js&quot;&gt;sitename&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;      title&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; article&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-property z-js&quot;&gt;title&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;      description&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; article&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-property z-js&quot;&gt;description&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;      type&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;article&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;      ...&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-variable z-other z-readwrite&quot;&gt;(url&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; &amp;amp;&amp;amp;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; {&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt; url&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; }&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;      images&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; [&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;        {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;          url&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt; ogImageUrl&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;          width&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 1200&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;          height&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 630&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;          alt&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; siteConfig&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-property z-js&quot;&gt;sitename&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;        },&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;      ]&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    },&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;    &#x2F;&#x2F; 他にも必要なメタデータがあれば追加可能&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;  };&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Next.jsがOGPのヘッダを生成する&lt;code&gt;openGraph&lt;&#x2F;code&gt;関数を提供しているので呼び出してい
るだけです。記事自体のフルパスが必要ですが、面倒なので記事内でパスを渡すよう
にしました。&lt;&#x2F;p&gt;
&lt;p&gt;また、MDXファイル内の&lt;code&gt;Image&lt;&#x2F;code&gt;で参照している画像のフルパスはこの処理では得られ
ないので、仕方なく固定の画像を指定しています。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;まとめ&quot;&gt;まとめ&lt;&#x2F;h2&gt;
&lt;p&gt;自身はたまにBlueskeyにリンクを投稿するくらいなので、それほど必要性は高くあり
ませんが、実装自体は簡単なので対応しているの越したことはありませんね。&lt;&#x2F;p&gt;
</content>
        <summary type="html">このブログは適当に実装したので、Open Graph Protocolに対応してしていませんでした。今更ですが、Open Graph Protorol対応しSNSでリンクを投稿した時に記事情報が表示できるようにしてみました。</summary>
        </entry><entry xml:lang="en">
        <title>NHK vs 日本IBM：89億円案件の破綻を勝手に思考する</title>
        <published>2025-03-31T00:00:00+00:00</published>
        <updated>2025-03-31T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2025/03/nhk-ibm/" type="text/html"/>
        <id>https://codedchords.dev/blog/2025/03/nhk-ibm/</id>
        
            <content type="html">&lt;!-- textlint-disable --&gt;
&lt;img
  src=&quot;https:&amp;#x2F;&amp;#x2F;codedchords.dev&amp;#x2F;blog&amp;#x2F;2025&amp;#x2F;03&amp;#x2F;nhk-ibm&amp;#x2F;nhk.webp?h=e0aa354dcd527f1b3952&quot;
  alt=&quot;NHK問題&quot; width=&quot;1456&quot; height=&quot;816&quot; loading=&quot;lazy&quot;
&#x2F;&gt;&lt;!-- textlint-enable --&gt;
 &lt;details&gt;
  &lt;summary&gt;Table of Contents&lt;&#x2F;summary&gt;
  &lt;!-- toc --&gt;
  &lt;&#x2F;details&gt;
&lt;p&gt;日本放送協会（NHK）がシステム開発の中止を巡り日本IBMを提訴しています。以前日
本IBMに勤務していた経験があり関わりもあったため気になったのでまとめてみまし
た。ただし、すでに日本IBMを離れて3年以上経過しており、内部事情を知る立場には
ありません。あくまで報道を読んだ第三者としての感想にすぎないことをご了承くださ
い。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;経緯&quot;&gt;経緯&lt;&#x2F;h2&gt;
&lt;p&gt;日本放送協会（NHK）がシステム開発の中止を巡り日本IBMを提訴しています。以前日
本IBMに勤務していた経験があり関わりもあったため気になったのでまとめてみまし
た。ただし、すでに日本IBMを離れて3年以上経過しており、内部事情を知る立場には
ありません。あくまで報道を読んだ第三者としての見解であることをご了承くださ
い。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;プロジェクトの背景と計画&quot;&gt;プロジェクトの背景と計画&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;NHKは富士通製メインフレームで稼働する営業基幹システムの刷新を計画。富士通
製メインフレームがEOLを迎える2027年3月末までに現行システムを別のプラット
フォームに移行する必要があった。&lt;&#x2F;li&gt;
&lt;li&gt;対象となった業務システムは、メインフレーム上を中心に構築された「営業基幹シ
ステム（EGGS）」。同システムは受信契約者の契約情報の管理や受信料の請求処理な
ど、NHKの受信料関係業務全般を支えている。2001年8月から20年以上稼働しており、
度重なる更改を経てきた。&lt;&#x2F;li&gt;
&lt;li&gt;NHKはこのシステムをオープン系に移行することを決め、プラットフォームとして
Google Cloud Platform（以降、 GCP）を選択。GCPの採用理由は「当協会の別システム
で利用実績があった」ためと報道されている。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;移行準備と入札&quot;&gt;移行準備と入札&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;NHKは2020年8月、アクセンチュアの支援を受けて要件定義書の作成に着手。同定義
書によると、移行対象となるプログラムは約1030万ステップ。&lt;&#x2F;li&gt;
&lt;li&gt;ホスト側のプログラムには、COBOLやJCL（ジョブ制御言語）、ADL（Aim
Description Language）、アセンブラーなどが約790万ステップ。&lt;&#x2F;li&gt;
&lt;li&gt;ホストと接続するクライアント側には、PowerCOBOLやC、C++ で記述したプログラ
ム（約240万ステップ）などがあった。&lt;&#x2F;li&gt;
&lt;li&gt;2022年9月、NHKは新システムへの移行業務について公開入札を開始。入札したのは
日本IBMを含む3社。2022年12月に委託金額89億5842万6004円（税込み）で日本IBMが
受注。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;プロジェクトの進行と問題発生&quot;&gt;プロジェクトの進行と問題発生&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;日本IBMは2023年1月からプロジェクトを開始。2023年3月末までに現行システムの
分析や移行計画の妥当性を判断するアセスメント工程を完了。&lt;&#x2F;li&gt;
&lt;li&gt;日本IBMは対象システムの「業務管理機能(約40万ステップ)」をリライト方式で移
行することとし、2023年4月から2024年2月末までにアーキテクチャー設計・基本設計
を完了。&lt;&#x2F;li&gt;
&lt;li&gt;リライトについて、ハンガリーのFreeSoftも担当することになった。&lt;&#x2F;li&gt;
&lt;li&gt;ところが2024年3月になって日本IBMは詳細設計に進めず、「最低16カ月の延伸が必
要」とNHKに通知。&lt;&#x2F;li&gt;
&lt;li&gt;その後代替策を模索するも、2024年5月に日本IBMは18ヶ月の延伸が必須で予定の納
期遵守が難しいことを通告。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;契約解除と提訴&quot;&gt;契約解除と提訴&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;これを受け、2024年8月にNHKはEOLまでに移行はできないと判断し日本IBMとの業務
委託契約を解除。&lt;&#x2F;li&gt;
&lt;li&gt;NHKは2025年2月3日付で日本IBMを提訴。システム開発の業務委託契約の解除に伴う
支払い済み代金の返還と損害賠償を求め、請求額は54億6992万7231円。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;クラウド基盤への移行業務を日本IBMに委託しましたが、上記のようプロジェクトは難航しました。
昨年、納期に間に合わないことが判明し、日本IBMとの委託契約解除に至ります。
NHKは54億円の損害賠償を請求し、日本IBMも真っ向から反論している状況です。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;個人的な評価&quot;&gt;個人的な評価&lt;&#x2F;h2&gt;
&lt;p&gt;経緯を整理してみても、責任の所在や意思決定プロセスには不明瞭な点が多く、特に
「誰が移行方式を最終決定したのか」という重要な点さえ判然としません。公開情報
だけでは全体像の把握は難しいものの、この事例から読み取れる教訓と問題点につい
て、IT業界での経験を踏まえて私見を述べたいと思います。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;NHKについて&quot;&gt;NHKについて&lt;&#x2F;h3&gt;
&lt;p&gt;ITプロジェクトに関わった経験がある人であれば、「NHKはプロジェクトを適切に統制できていなかったのではないか」という印象を持つでしょう。&lt;&#x2F;p&gt;
&lt;h4 id=&quot;高リスクプロジェクトの体制不備&quot;&gt;高リスクプロジェクトの体制不備&lt;&#x2F;h4&gt;
&lt;p&gt;20年以上運用してきたメインフレームの業務システムを別のプラットフォームに移
行するという作業は、本質的に高リスクなプロジェクトです。このような移行を成功
させるためには、最低でも以下が前提条件となります。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;現行システムの機能要件の完全な把握&lt;&#x2F;li&gt;
&lt;li&gt;システム内部構造の詳細な理解&lt;&#x2F;li&gt;
&lt;li&gt;業務ロジックに関する十分な知見&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;今回の事例では、現行システムの開発・保守を担当し、これらの知見を有していたであろう富士通ではなく、日本IBMが移行を担当することになりました。このような状況で成功するためには、NHK自身が十分な知見を持ち、プロジェクトに積極的に関与することが不可欠だったはずです。&lt;&#x2F;p&gt;
&lt;p&gt;しかし経緯を見る限り、NHKは日本IBMに発注した後、主導的な役割を果たさず「委託して任せる」というスタンスだったのではないかと推察されます。&lt;&#x2F;p&gt;
&lt;h4 id=&quot;組織改革の影響&quot;&gt;組織改革の影響&lt;&#x2F;h4&gt;
&lt;p&gt;この移行の要件定義とIBMへの発注が決まった2020年〜2023年の時期は、前田晃
伸氏が会長を務め、多数のコンサルタントを起用して中期経営計画のもとダウンサイ
ジングと構造改革を推進していた時期と重なります。これを考慮すると、以下のよう
な懸念が浮かび上がります。&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;意思決定の歪み&lt;&#x2F;strong&gt;: 移行方式がアーキテクチャー上の合理性よりも、組織内の政治的動向によって決定された可能性&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;知識の流出&lt;&#x2F;strong&gt;: 50歳以上の早期退職や管理職の大幅削減（3割）の結果、以下のような問題が生じた可能性&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;基幹システムのプロジェクトを適切に統制するノウハウの喪失&lt;&#x2F;li&gt;
&lt;li&gt;各業務に関連した要件を検証するための深い知識の流出&lt;&#x2F;li&gt;
&lt;li&gt;システム移行に必要な経験を持つ人材の減少&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;h4 id=&quot;リーダーシップの問題&quot;&gt;リーダーシップの問題&lt;&#x2F;h4&gt;
&lt;p&gt;前田晃伸氏は富士銀行出身で、最終的にみずほフィナンシャルグループの社長・会長
を務めた人物です。彼の在任中、みずほは2000年代に勘定系システムの統合で大規
模な障害を経験しています。
&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.mizuhobank.co.jp&#x2F;company&#x2F;release&#x2F;bk&#x2F;2011&#x2F;pdf&#x2F;news110520_4.pdf&quot;&gt;みずほ自身のシステム障害特別調査委員会の報告&lt;&#x2F;a&gt;
や&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.shippai.org&#x2F;fkd&#x2F;cf&#x2F;CA0000623.html&quot;&gt;日経クロステックの記事&lt;&#x2F;a&gt;に
よると、その障害の主な原因は次の通りとされました。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;現行システムに対する知見の欠如&lt;&#x2F;li&gt;
&lt;li&gt;危機的状況に対応できる組織力の欠如&lt;&#x2F;li&gt;
&lt;li&gt;経営層のIT統制力の欠如&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;これらの問題点は、今回のNHKの事例にも当てはまる可能性があります。経験豊富なシニア層の人員整理、富士通から日本IBMへの移行担当の変更、そして安易に大胆な移行方針を許容する経営判断というパターンが、みずほの過去の失敗と類似しています。&lt;&#x2F;p&gt;
&lt;p&gt;現在の契約解除により移行計画は頓挫していますが、2027年のEOLは確実に迫ってい
ます。NHKは今後どのような対応をとるのか、注目される点です。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;IBMについて&quot;&gt;IBMについて&lt;&#x2F;h3&gt;
&lt;p&gt;プロジェクトを十分に管理できなかったクライアント側に対してベンダーとして同情すべき点はありますが、日本IBM側にも以下のような問題点があったと考えられます。&lt;&#x2F;p&gt;
&lt;h4 id=&quot;プロジェクト受注の判断&quot;&gt;プロジェクト受注の判断&lt;&#x2F;h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;高リスクプロジェクトの安易な受注&lt;&#x2F;strong&gt;: 富士通が開発・保守し、アクセンチュア
が要件定義を実施した大規模システムの移行プロジェクトは本質的に超ハイリスクで
す。このような状況下でプロジェクトを受注すること自体、リスク管理の観点から疑
問が残る。&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;アセスメント期間の不足&lt;&#x2F;strong&gt;: 2023年1月から3月末までの約3か月間でのアセスメ
ント工程は、1000万ステップを超える大規模システムの分析としては明らかに短すぎ
ました。事実、後に要件定義では明らかになっていなかった文書化されていない仕様
や変更が浮上している。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h4 id=&quot;見積りと実行体制の問題&quot;&gt;見積りと実行体制の問題&lt;&#x2F;h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;予算の不足&lt;&#x2F;strong&gt;: 40万ステップのリライト方式による移行に対して約90億円弱とい
う見積もりは、プロジェクトの複雑さを考慮すると低く見積もりすぎた可能性がある&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;パートナー選定の疑問&lt;&#x2F;strong&gt;: メインフレームからのモダナイゼーションに実績のあ
るTISなどの国内企業ではなく、実績が不明確なハンガリーのFreeSoftを選定した理
由が不明。特に過去にも同様の失敗事例があったにもかかわらず、このような選
択をした判断には疑問が残る&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h4 id=&quot;組織的課題&quot;&gt;組織的課題&lt;&#x2F;h4&gt;
&lt;p&gt;おそらく日本IBM内ではコミュニケーションセクターがこのプロジェクトを担当して
いたと推測されますが、金融セクターなどと比較すると大型案件の経験が少なく、こ
のような複雑な移行プロジェクトに対する十分な経験者も不足していた可能性があり
ます。それにもかかわらず、受注に踏み切ってしまったことが、後の問題につながっ
たのではないでしょうか。&lt;&#x2F;p&gt;
&lt;p&gt;同時に、移行の複雑さを当初から認識していたにもかかわらず、クライアントに対し
て十分なリスク説明や実現可能な代替案の提示が不足していた可能性も否定できませ
ん。大規模プロジェクトでは、技術的な実行能力だけでなく、リスクの透明な伝達と
現実的な期待値の設定も成功の鍵となります。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;リライト方式の移行について&quot;&gt;リライト方式の移行について&lt;&#x2F;h2&gt;
&lt;p&gt;メインフレームのシステムは富士通の撤退などもあり、多くの企業がライフサイクル終了に向けた対応を迫られています。こうした状況下で、「リライト方式」によるオープン系やクラウドへの移行を実施・計画している企業は少なくありません。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;リライト方式とは&quot;&gt;リライト方式とは&lt;&#x2F;h3&gt;
&lt;p&gt;リライト方式とは、既存のメインフレームのコードから機能や要件を分析し、現代の
技術、言語、アーキテクチャーを使ってシステムを一から再設計していく手法です。
一般的な流れは次の通りです。&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;既存コードの自動分析（パターン認識やAI、機械学習などを利用したツールの活用）&lt;&#x2F;li&gt;
&lt;li&gt;ビジネスルールや処理ロジックの抽出&lt;&#x2F;li&gt;
&lt;li&gt;コード変換ツールを用いたJavaなどの現代的言語への自動変換&lt;&#x2F;li&gt;
&lt;li&gt;必要に応じた調整と最適化&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;h3 id=&quot;リライト方式の問題点&quot;&gt;リライト方式の問題点&lt;&#x2F;h3&gt;
&lt;p&gt;私はメインフレームでの開発・保守経験と、現代的な言語やフレームワークでの開発
経験の両方を持つ立場から、このリライト方式には以下のような本質的な問題がある
と考えています。&lt;&#x2F;p&gt;
&lt;h4 id=&quot;暗黙知の喪失&quot;&gt;暗黙知の喪失&lt;&#x2F;h4&gt;
&lt;p&gt;コード分析では、コードに埋め込まれた文書化されていない次のような
「暗黙知」を十分に捉えることができません。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;ビジネスルールの背景にある理由&lt;&#x2F;li&gt;
&lt;li&gt;例外処理が導入された経緯&lt;&#x2F;li&gt;
&lt;li&gt;特定の実装が選ばれた理由&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;これらの理解がないまま移行すると、移行後のシステム維持できない可能性があります。&lt;&#x2F;p&gt;
&lt;h4 id=&quot;保守性の低下&quot;&gt;保守性の低下&lt;&#x2F;h4&gt;
&lt;p&gt;コード変換ツールによって生成されたコードには以下のような問題が生じがちです。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;可読性の低さ（人間による理解が困難）&lt;&#x2F;li&gt;
&lt;li&gt;非効率な構造やアルゴリズム&lt;&#x2F;li&gt;
&lt;li&gt;デバッグや修正の困難さ&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;つまり、移行が完了したとしても、その後の保守作業は極めて難しくなる可能性があります。&lt;&#x2F;p&gt;
&lt;h4 id=&quot;技術的負債の継承&quot;&gt;技術的負債の継承&lt;&#x2F;h4&gt;
&lt;p&gt;現行システムの非効率で古い設計思想がそのまま新しいプラットフォームに移植され
てしまいます。これは本来、システム刷新の大きな目的である技術的負債の解消とい
う利点を失うことを意味します。&lt;&#x2F;p&gt;
&lt;h4 id=&quot;新たな依存性の導入&quot;&gt;新たな依存性の導入&lt;&#x2F;h4&gt;
&lt;p&gt;コード変換ツールはしばしば固有のランタイムやライブラリに依存します。&lt;&#x2F;p&gt;
&lt;p&gt;「メインフレーム」という特定プラットフォームの縛りから逃れるために導入したは
ずが、さらに短い寿命、かつ保守が難しい可能性のある別の依存関係を作り出してしまう
矛盾が生じます。&lt;&#x2F;p&gt;
&lt;h4 id=&quot;組織的スキルの阻害&quot;&gt;組織的スキルの阻害&lt;&#x2F;h4&gt;
&lt;p&gt;要件定義・設計をIT担当者が経験できず、新しいプラットフォームに対する実践的な
知識やスキルが組織内に蓄積されません。結果として、移行後も組織としての技術的
対応力が向上しない状態に陥ります。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;総合的評価&quot;&gt;総合的評価&lt;&#x2F;h3&gt;
&lt;p&gt;以上を踏まえると、リライト方式は短期的には魅力的に見えるます。
しかし、長期的には割に合わないものと思えます。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;移行プロジェクト自体のリスクが高い&lt;&#x2F;li&gt;
&lt;li&gt;移行が成功したとしても、保守性や拡張性に深刻な問題を抱えたシステムになる可能性が高い&lt;&#x2F;li&gt;
&lt;li&gt;組織としての技術力向上や知識蓄積に寄与しない&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;では、どうすべきか&quot;&gt;では、どうすべきか&lt;&#x2F;h2&gt;
&lt;p&gt;私は「&lt;strong&gt;グリーンフィールド開発&lt;&#x2F;strong&gt;」(Greenfield Development)しかないのかなと思います。&lt;&#x2F;p&gt;
&lt;p&gt;グリーンフィールド開発は、具体的には次のようなものです。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;既存コードを参照せず、現在のビジネス要件を基に新たに要件定義フェースを行う。&lt;&#x2F;li&gt;
&lt;li&gt;レガシーシステムの制約や過去の設計判断に縛られない。&lt;&#x2F;li&gt;
&lt;li&gt;最新技術やアーキテクチャを自由に選択する。&lt;&#x2F;li&gt;
&lt;li&gt;ビジネスプロセス自体の見直しや最適化も同時に行う。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;「リライト方式」との違いは、リライトが既存システムの機能を基準に再構築するのに対し、グリーンフィールド開発は既存システムの機能にこだわらず、現在のビジネスニーズから改めて考え直す点です。当然、要件定義からやり直すため、より多くの時間とステークホルダーの関与が必要になります。&lt;&#x2F;p&gt;
&lt;p&gt;しかし、以下のように考えてどうでしょう。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;企業の競争力の源泉とならないシステム
&lt;ul&gt;
&lt;li&gt;独自の社内システムは捨て、システム移行でなく&lt;strong&gt;カスタマイズしない&lt;&#x2F;strong&gt;SaaSなどに置き換えるリエンジニアリングで対応する。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;企業の競争力を生み出すシステム
&lt;ul&gt;
&lt;li&gt;要件を理解しておくことは、いずれにしろ企業として必須。ならば、コードから逆算するのでなく、要件をきちんと今のビジネスに合わせて定義したほうがよい&lt;&#x2F;li&gt;
&lt;li&gt;要件定義をゼロから実施することで、要件定義の知見も社内に蓄積される&lt;&#x2F;li&gt;
&lt;li&gt;必要であればリライトで使われる分析ツールを併用して、要件定義の補強として使えば良い&lt;&#x2F;li&gt;
&lt;li&gt;肝は要件定義フェーズを行うことで、&lt;strong&gt;アーキテクティングや設計を確実に実施できる&lt;&#x2F;strong&gt;こと&lt;&#x2F;li&gt;
&lt;li&gt;アーキテクティングや設計ができれば、あとは普通の開発&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;どうでもよいシステムでも最初抵抗があるかもしれません。しかし、SaaSなどに乗り換え
ることでシステムに縛られず身軽になれます。&lt;&#x2F;p&gt;
&lt;p&gt;競争力を生み出すシステムはビジネスからの要求の変化も激しいので、要件定義から開発までスピードを持ってできる対応力がITにも問われているはずです。これを機にゼロから開発するほうがシステムの文書化、知見やスキルの蓄積もでき結果的にはお手軽に移行するより良い結果を生むと思います。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;結論&quot;&gt;結論&lt;&#x2F;h2&gt;
&lt;p&gt;NHKと日本IBMの訴訟は、大規模システム移行プロジェクトが孕む本質的な課題を浮き
彫りにしています。長年運用された基幹システムの移行には、組織の体制、プロジェ
クト管理の手法、そして技術的なアプローチの全てが適切に機能する必要がありま
す。&lt;&#x2F;p&gt;
&lt;p&gt;今回の事例では、NHK側の要件理解とプロジェクト統制、IBM側の計画策定とリスク評
価、そして双方のコミュニケーションのいずれにも課題があったように見受けられま
す。訴訟の行方はともかく、メインフレームEOLという避けられない課題に対して、
NHKは今後どのような戦略で対応していくのか注目されます。&lt;&#x2F;p&gt;
&lt;p&gt;システム移行の方法論としてのリライト方式についての考察は、この事例から派生し
た1つの視点に過ぎませんが、多くの組織が直面している課題にも当てはまるのでは
ないと思います。&lt;&#x2F;p&gt;
</content>
        <summary type="html">NHKが日本IBMに対して54億円の損害賠償を求めて提訴した大型システム移行の失敗。元IBM社員の視点から、組織管理の問題点、プロジェクトが頓挫した原因、そして2027年に迫るメインフレームEOLへの対応策を勝手に検討してみました。</summary>
        </entry><entry xml:lang="en">
        <title>Claude CodeをMCPサーバーとして利用する利点</title>
        <published>2025-03-29T00:00:00+00:00</published>
        <updated>2025-03-29T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2025/03/mcp-integration-of-claude-code-inkdrop/" type="text/html"/>
        <id>https://codedchords.dev/blog/2025/03/mcp-integration-of-claude-code-inkdrop/</id>
        
            <content type="html">&lt;p&gt;&lt;a href=&quot;&#x2F;articles&#x2F;2025&#x2F;03&#x2F;28&#x2F;claude-integration-with-inkdrop&quot;&gt;前回の記事&lt;&#x2F;a&gt;では、 InkdropとClaude Desktopの統合について紹介しました。今回は一歩進んで、Claude CodeをMCPサーバーとして活用する方法とそのメリットについて詳しく解説します。&lt;&#x2F;p&gt;
&lt;!-- toc --&gt;
&lt;h2 id=&quot;MCP_ServerにもなれるClade_Code&quot;&gt;MCP ServerにもなれるClade Code&lt;&#x2F;h2&gt;
&lt;p&gt;Claude Codeを頻繁に活用することでAnthropicへの支払いコストが増加していますが、一度使い始めるとコーディング作業では手放せなくなりつつあります。&lt;&#x2F;p&gt;
&lt;p&gt;そのClaude Codeは、MCP Clientになれることは知っていました。
しかし、&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;code.claude.com&#x2F;docs&#x2F;en&#x2F;mcp&quot;&gt;公式ドキュメント&lt;&#x2F;a&gt;を読んでいてMCP Serverにもなれるというチュートリアルを発見しました。&lt;&#x2F;p&gt;
&lt;p&gt;次のコマンドでMCP Serverとして起動できます。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;claude&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; mcp serve&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;Claude_DesktopにClaude_CodeをMCP_Serverとして登録&quot;&gt;Claude DesktopにClaude CodeをMCP Serverとして登録&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;a href=&quot;&#x2F;articles&#x2F;2025&#x2F;03&#x2F;28&#x2F;claude-integration-with-inkdrop&quot;&gt;Inkdropと同様&lt;&#x2F;a&gt;に、Claude Desktopに
Claude CodeをMCP Serverとして登録します。&lt;&#x2F;p&gt;
&lt;p&gt;また、&lt;code&gt;bash&lt;&#x2F;code&gt;の問題が起きそうだったので、例のごとくシェルスクリプトでWrapし&lt;code&gt;~&#x2F;bin&#x2F;claude-code-mcp&lt;&#x2F;code&gt;というファイル名で配置し実行権限を付けした。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-shebang z-shell z-meta z-shebang z-shell&quot;&gt;#!&#x2F;usr&#x2F;bin&#x2F;env fish&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;claude&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; mcp serve&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;作成したスクリプトを指定して、Claude Desktopの設定ファイル &lt;code&gt;~&#x2F;Library&#x2F;Application Support&#x2F;Claude&#x2F;claude_desktop_config.json&lt;&#x2F;code&gt;に追加します。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;json&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;  &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;mcpServers&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;: {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;inkdrop&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;: {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;      &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;command&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;&#x2F;Users&#x2F;foo&#x2F;bin&#x2F;inkdrop-mcp&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;      &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;args&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;: [],&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;      &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;env&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;: {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;        &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;INKDROP_LOCAL_SERVER_URL&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;http:&#x2F;&#x2F;localhost:19840&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;        &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;INKDROP_LOCAL_USERNAME&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;foo&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;        &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;INKDROP_LOCAL_PASSWORD&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;bar&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;      }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    },&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;claude_code&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;: {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;      &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;command&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;&#x2F;Users&#x2F;foo&#x2F;bin&#x2F;claude-code-mcp&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;      &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;args&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;: [],&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;      &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;env&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;: {}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;  }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;Claude_DesktopからClaude_Codeにコード分析を依頼&quot;&gt;Claude DesktopからClaude Codeにコード分析を依頼&lt;&#x2F;h2&gt;
&lt;p&gt;Claude CodeをClaude Desktopに正常に接続できたことを確認したので、次のステップとして実際にこのブログサイトのコードの分析を依頼してみます。&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Claude Desktopのチャットインターフェースで、Claude Codeにアクセスするためのプロンプトを入力&lt;&#x2F;li&gt;
&lt;li&gt;分析したいプロジェクトのパスを明示的に指定&lt;&#x2F;li&gt;
&lt;li&gt;フォルダ階層の確認を依頼&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;初回実行時には、Claude Codeがファイルシステムにアクセスするための許可を求めるプロンプトが数回表示されました。これは、セキュリティ上の理由から必要な確認プロセスです。許可を与えると、Claude Codeは指定されたプロジェクトフォルダにアクセスし、次のよう分析しました。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;私：claude_code内の~&#x2F;ghq&#x2F;github.com&#x2F;foo&#x2F;blog-source&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    のプロジェクトにアクセスできますか？&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    また、プロジェクト内のフォルダ階層はどうなっていますか？&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;Users&#x2F;foo&#x2F;ghq&#x2F;github.com&#x2F;foo&#x2F;blog-sourceにアクセスできました。&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;これはパーソナルブログのソースコードです。&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;ブログの主な特徴：&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Next.js 15, React 19, TypeScript, Tailwind CSSで構築&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;MDXサポートで記事を書いている&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;レスポンシブデザイン&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;ダークモード対応&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;RSS、コードシンタックスハイライト、Giscusコメントシステム、&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;ソーシャルリンク、SoundCloudの埋め込み、Whisper機能、目次機能など&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;サイト設定では「Coded Chords」という名前のブログで、&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;著者は「Toshiyuki Yoshida」です。&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;(以下、省略)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;Claude_Desktop&#x2F;Claude_Code&#x2F;InkdropのMCP統合&quot;&gt;Claude Desktop&#x2F;Claude Code&#x2F;InkdropのMCP統合&lt;&#x2F;h2&gt;
&lt;p&gt;Claude DesktopにはInkdropもMCP Serverとして登録されているので、コード解析結果をInkdropに記録させることもできます。&lt;&#x2F;p&gt;
&lt;p&gt;次のようにClaude Desktopで依頼してみました。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;では、プロジェクト概要とプロジェクトのフォルダ構成について、&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;第三者が理解しやすいようサマリーを inkdrop内のNotebook Inboxに&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;「ブログの概要」というタイトルで作成してください。&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;なお、形式はMarkdownを使用してください。&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;結果、Claude Codeから取得し分析した結果、Markdown形式でInkdropのNoteとしてドキュメント化してくれました。&lt;&#x2F;p&gt;
&lt;p&gt;プロジェクト概要は&lt;code&gt;README.md&lt;&#x2F;code&gt;から読み取ったようですが、特筆すべきは、フォルダ構成や各ディレクトリの役割、記事管理の仕組みまで正確に把握・文書化している点です。&lt;&#x2F;p&gt;
&lt;p&gt;仕組みとしては全体像をダイアグラムにしてみました。次の通りです。&lt;&#x2F;p&gt;
&lt;!-- textlint-disable --&gt;


&lt;noscript&gt;
    &lt;strong&gt;⚠️ JavaScript is required to render the diagram.&lt;&#x2F;strong&gt;
&lt;&#x2F;noscript&gt;
&lt;pre class=&quot;mermaid invertible-image&quot;&gt;
    flowchart TB
UserReq[ユーザーリクエスト&#x2F;指示]
CD[Claude Desktop]
CC[Claude Code]
BlogRepo[ブログリポジトリ]
InkdropMCP[inkdropapp&#x2F;mcp-server]

    subgraph Inkdrop[Inkdropアプリ]
        API[HTTP API]
        Notes[ノート]
    end

    %% 通常フロー
    UserReq --&gt;|会話形式の指示| CD
    CD --&gt;|コード分析のリクエスト| CC
    CC --&gt;|ファイル読み取り| BlogRepo
    BlogRepo --&gt;|コードとファイル内容| CC
    CC --&gt;|分析結果| CD

    %% ファイル操作フロー
    CC --&gt;|新記事作成| BlogRepo

    %% Inkdrop連携フロー
    CD --&gt;|ノート作成リクエスト| InkdropMCP
    InkdropMCP --&gt;|APIリクエスト| API
    API --&gt;|ノートデータ保存| Notes

    %% スタイル
    classDef claudeDesktop fill:#f9a8d4,stroke:#be185d,stroke-width:2px
    classDef claudeCode fill:#93c5fd,stroke:#2563eb,stroke-width:2px
    classDef inkdropCompo fill:#ffffff,stroke:#6b7280,stroke-width:1px
    classDef repository fill:#fcd34d,stroke:#d97706,stroke-width:2px
    classDef mcpServer fill:#93c5fd,stroke:#2563eb,stroke-width:2px
    classDef other fill:#e5e7eb,stroke:#6b7280,stroke-width:2px

    class CD claudeDesktop
    class CC,InkdropMCP claudeCode
    class API,Notes inkdropCompo
    class Inkdrop,BlogRepo repository
    class UserReq other

`
&lt;&#x2F;pre&gt;
&lt;!-- textlint-enable --&gt;
&lt;p&gt;便利です。&lt;&#x2F;p&gt;
&lt;p&gt;開発プロジェクトのドキュメンテーションや&lt;code&gt;README.md&lt;&#x2F;code&gt;の作成など、次のようなワークフローにすると大変スマートに仕事が進みそうです。&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Claude DesktopからClaude Codeにリポジトリーからコード情報を収集し、そのコードを分析しMarkdown文書を生成しInkdropにNote作成させる。&lt;&#x2F;li&gt;
&lt;li&gt;Inkdrop上でMarkdown文書をPreviewで確認し、必要に応じて編集する&lt;&#x2F;li&gt;
&lt;li&gt;Claude DesktopからInkdrop上のNoteからドキュメントを収集し、Claude Codeを通じてリポジトリーにドキュメントとして格納させる&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;h2 id=&quot;Claude_Code_MCP_Server利用コスト&quot;&gt;Claude Code MCP Server利用コスト&lt;&#x2F;h2&gt;
&lt;p&gt;Claude CodeをMCP ServerとしてClaude Desktopから利用した際のコストを確認してみました。&lt;&#x2F;p&gt;
&lt;p&gt;Claude Codeをコマンドラインから普通に使うと、MODELとして &lt;code&gt;claude-3-7-sonnet-20250219&lt;&#x2F;code&gt;が使用されています。
このため、多用しているとクレジットも大量に消費されていきます。
しかし、Claude CodeをMCP Serverとして使うと、リクエストあるからと言ってClaude Codeから
MODELを使用したリクエストが出るわけでも無さそうです。またリクエストが出たとしても、今のところ&lt;code&gt;claude-3-5-haiku-20241022&lt;&#x2F;code&gt;しか利用されていません。
Tailwind Plusで提供されるコードが大量にlintで引っかかるので修正をClaud
Destop経由で行いましたが、同様Claude Codeからは&lt;code&gt;claude-3-5-haiku-20241022&lt;&#x2F;code&gt;を
利用するリクエストかでていませんでした。&lt;&#x2F;p&gt;
&lt;p&gt;Claude CodeをMCP Serverとして利用する場合、提供されるツールは以下のとおりです。これらのうち、AgentTool以外の大半はClaude Code内部で処理が完結するため、高度な分析などはClaude Desktop側から直接リクエストされると考えられます。&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Tool&lt;&#x2F;th&gt;&lt;th&gt;Description&lt;&#x2F;th&gt;&lt;th&gt;Permission Required&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;AgentTool&lt;&#x2F;td&gt;&lt;td&gt;Runs a sub-agent to handle complex, multi-step tasks&lt;&#x2F;td&gt;&lt;td&gt;No&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;BashTool&lt;&#x2F;td&gt;&lt;td&gt;Executes shell commands in your environment&lt;&#x2F;td&gt;&lt;td&gt;Yes&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;GlobTool&lt;&#x2F;td&gt;&lt;td&gt;Finds files based on pattern matching&lt;&#x2F;td&gt;&lt;td&gt;No&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;GrepTool&lt;&#x2F;td&gt;&lt;td&gt;Searches for patterns in file contents&lt;&#x2F;td&gt;&lt;td&gt;No&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;LSTool&lt;&#x2F;td&gt;&lt;td&gt;Lists files and directories&lt;&#x2F;td&gt;&lt;td&gt;No&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;FileReadTool&lt;&#x2F;td&gt;&lt;td&gt;Reads the contents of files&lt;&#x2F;td&gt;&lt;td&gt;No&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;FileEditTool&lt;&#x2F;td&gt;&lt;td&gt;Makes targeted edits to specific files&lt;&#x2F;td&gt;&lt;td&gt;Yes&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;FileWriteTool&lt;&#x2F;td&gt;&lt;td&gt;Creates or overwrites files&lt;&#x2F;td&gt;&lt;td&gt;Yes&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;NotebookReadTool&lt;&#x2F;td&gt;&lt;td&gt;Reads and displays Jupyter notebook contents&lt;&#x2F;td&gt;&lt;td&gt;No&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;NotebookEditTool&lt;&#x2F;td&gt;&lt;td&gt;Modifies Jupyter notebook cells&lt;&#x2F;td&gt;&lt;td&gt;Yes&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;(2025-03-31追記)&lt;&#x2F;p&gt;
&lt;p&gt;その後、もう少し複雑な処理で確認しました。ソースを複雑に分析するような場合は、
Claude CodeでのリクエストからもMODELとして &lt;code&gt;claude-3-7-sonnet-20250219&lt;&#x2F;code&gt;が使用されていました。&lt;&#x2F;p&gt;
&lt;p&gt;依頼した処理は次のようなものです。&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;プロジェクトがOGP対応しているか、対応している場合はどのようなコンポーネントが関係しどのような仕様になっているか調査し、
InkdropのNotebook blogに新たに Noteを作成して仕様書にしてください。仕様書に
は静的モデルと動的モデルをMermaid でダイアグラム化してください。&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Claude DesktopがInkdropに書き出した文書をそのままPDFにしたものも&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;e.pcloud.link&#x2F;publink&#x2F;show?code=XZiJhdZ3UkXV7lTN8knDkuquFjN147NvQ0y&quot;&gt;公開&lt;&#x2F;a&gt;しておき
ます。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;まとめ&quot;&gt;まとめ&lt;&#x2F;h2&gt;
&lt;p&gt;Claude CodeのMCP Serverを利用する利点は2つです。&lt;&#x2F;p&gt;
&lt;p&gt;1つは、Claude Codeからのリクエスト発行を押さえ、Claude Desktopからのリクエストになることでの&lt;strong&gt;コスト削減&lt;&#x2F;strong&gt;が大きくできることです。
(2025-03-31追記) 処理内容によってはClaude Code側の処理でもSonnet 3.7が使用
されるため注意は必要です。&lt;&#x2F;p&gt;
&lt;p&gt;本来次のようにClaude DesktopとClaude Codeは使い分けるべきだと思います。&lt;&#x2F;p&gt;
&lt;dl&gt;
  &lt;dt&gt;**Claude Code**&lt;&#x2F;dt&gt;
  &lt;dd&gt;
    - コマンドライン志向
    - ファイルシステムへの直接アクセス
    - コードリポジトリとの統合
    - 開発タスクに特化
  &lt;&#x2F;dd&gt;
  &lt;dt&gt;**Claude Desktop**&lt;&#x2F;dt&gt;
  &lt;dd&gt;
    - GUI ベースの使いやすさ
    - 会話形式のインターフェース
    - 画像認識機能
    - 一般的な質問応答に最適
  &lt;&#x2F;dd&gt;
&lt;&#x2F;dl&gt;
&lt;p&gt;しかし、MCP統合によりファイルシステムへの直接アクセス、コードリポジトリとの統合のメリットを
Claude Desktopからも享受できるようになります。Claude Desktopは月額固定料金なので、ユーザーには非常に恩恵があります。&lt;&#x2F;p&gt;
&lt;p&gt;2つ目の利点は、&lt;strong&gt;ワークフロー改善の可能性&lt;&#x2F;strong&gt;です。
Claude CodeとInkdropの統合のような仕組みは、開発者のワークフローを大幅に改善する可能性を秘めており、以下のような発展が期待できそうです。&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;より高度なコンテキスト理解&lt;&#x2F;strong&gt;:
&lt;ul&gt;
&lt;li&gt;コードとドキュメントの関係性をより深く理解&lt;&#x2F;li&gt;
&lt;li&gt;プロジェクト全体の知識グラフ構築&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;自動ドキュメント更新&lt;&#x2F;strong&gt;:
&lt;ul&gt;
&lt;li&gt;コード変更に基づく関連ドキュメントの自動更新&lt;&#x2F;li&gt;
&lt;li&gt;コメントとドキュメントの一貫性維持&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;協調作業の強化&lt;&#x2F;strong&gt;:
&lt;ul&gt;
&lt;li&gt;チームメンバー間の知識共有と協調作業の促進&lt;&#x2F;li&gt;
&lt;li&gt;コードレビューとドキュメントレビューの統合&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;この統合は特に、複雑なプロジェクトやドキュメント駆動開発を実践している開発者にとって大きなメリットをもたらします。知識の管理と活用、コード生成、ドキュメント作成の一連のプロセスがシームレスに繋がることで、開発プロセス全体の質と効率が向上するでしょう。&lt;&#x2F;p&gt;
</content>
        <summary type="html">前回はInkdropとClaudeのMCP統合について紹介しましたが、今回はClaude Codeを MCPサーバーとして活用する方法とそのメリットについて解説します。 開発者にとって、Claude CodeとInkdropの組み合わせがどのように効率的な 知識管理と開発プロセスの向上につながるかを探ります。</summary>
        </entry><entry xml:lang="en">
        <title>InkdropとClaudeのMCP統合</title>
        <published>2025-03-28T00:00:00+00:00</published>
        <updated>2025-03-28T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2025/03/claude-integration-with-inkdrop/" type="text/html"/>
        <id>https://codedchords.dev/blog/2025/03/claude-integration-with-inkdrop/</id>
        
            <content type="html">&lt;p&gt;作者の方の記事「
&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.devas.life&#x2F;integrating-my-note-app-with-claudes-mcp&#x2F;&quot;&gt;Integrating my note app with Claude&#x27;s MCP&lt;&#x2F;a&gt;
」と&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=ou4BYmY8Dq0&amp;amp;t=116s&amp;amp;themeRefresh=1&quot;&gt;YouTube&lt;&#x2F;a&gt;
を参考にしながら、実際にmacOSで検証してみました。前提としてClaude Desktopが稼働している必要が
あります。
元記事が英語なので日本語でまとめてみました。&lt;&#x2F;p&gt;
&lt;!-- toc --&gt;
&lt;h2 id=&quot;メリットとユースケース&quot;&gt;メリットとユースケース&lt;&#x2F;h2&gt;
&lt;p&gt;実施するまえに、InkdropとClaudeが統合すると何がうれしいのでしょう？&lt;&#x2F;p&gt;
&lt;p&gt;MCP統合により、ClaudeがInkdropのノートに直接アクセスし検索・作成・更新が可能となります。
これにより、次のようなメリットがあります。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Claudeがユーザーの書きためた複数ノートの知見を横断的に分析・活用できる&lt;&#x2F;li&gt;
&lt;li&gt;InkdropのNote管理作業を自動化し効率化できる&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;例えば考えられるユースケースは、次のようなものです。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;パーソナル知識アシスタント&lt;&#x2F;strong&gt;
&lt;ul&gt;
&lt;li&gt;技術メモや学習ノートが蓄積されたInkdropで「JavaScriptのPromiseについて教えて」と質問すると、
Claudeはあなたの過去のノートから関連情報を抽出し、あなた自身の理解や用語に合わせた説明を提供。
さらに「これをプロジェクトXに適用するには？」と質問すると、プロジェクトXのノートも参照しながら具体的な実装アドバイスを返せる。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;スマートな情報整理と要約&lt;&#x2F;strong&gt;
&lt;ul&gt;
&lt;li&gt;「先月の週次会議ノートを要約して月次報告として重要なアクションアイテムを抽出し、新しいノートにまとめて」と指示すると、
Claudeは該当期間の会議ノートを検索・分析し、重要ポイントとアクションアイテムを抽出した新規ノートを自動生成。
定期的なレビューや進捗管理が効率化される。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;インストール手順&quot;&gt;インストール手順&lt;&#x2F;h2&gt;
&lt;p&gt;まず &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;inkdropapp&#x2F;mcp-server?tab=readme-ov-file&quot;&gt;Inkdrop MCP Server&lt;&#x2F;a&gt;をインストールします。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;npm&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; install -g @inkdropapp&#x2F;mcp-server&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;次にInkdrop内のHTTP Serverをセットアップのために、&lt;code&gt;config.json&lt;&#x2F;code&gt;を修正します。&lt;&#x2F;p&gt;
&lt;p&gt;Macの場合は&lt;code&gt;~&#x2F;Library&#x2F;Application Support&#x2F;inkdrop&#x2F;&lt;&#x2F;code&gt; です。&lt;&#x2F;p&gt;
&lt;p&gt;Inkdropを修了させて、既存の設定を壊さないように次の設定を追加します。&lt;code&gt;username&lt;&#x2F;code&gt;と&lt;code&gt;password&lt;&#x2F;code&gt;の設定は例なので、ちゃんと書き換えましょう。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;json&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;  &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;: {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;core&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;: {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;      &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;server&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;: {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;        &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;enabled&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language z-json&quot;&gt; true&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;        &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;port&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 19840&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;        &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;bindAddress&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;127.0.0.1&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;        &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;auth&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;: { &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;username&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;foo&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;password&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;bar&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;      }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;  }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;設定したら、Inkdropを起動し次のコマンドで確認できます。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;curl&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; -v -u foo:bar http:&#x2F;&#x2F;localhost:19840&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# -&amp;gt; {&amp;quot;version&amp;quot;:&amp;quot;5.10.0&amp;quot;,&amp;quot;ok&amp;quot;:true}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;code&gt;{&quot;version&quot;:&quot;5.10.0&quot;,&quot;ok&quot;:true}&lt;&#x2F;code&gt;と表示されればOKです。&lt;&#x2F;p&gt;
&lt;p&gt;次にCladue Desktopの設定が必要ですが、Claudeがどうもシェルに&lt;code&gt;bash&lt;&#x2F;code&gt;が使用されていることを前提としているため、
「&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.devas.life&#x2F;integrating-my-note-app-with-claudes-mcp&#x2F;&quot;&gt;Integrating my note app with Claude&#x27;s MCP&lt;&#x2F;a&gt;」の記事通りに設定しても動作しませんでした。&lt;&#x2F;p&gt;
&lt;p&gt;シェルの問題を回避するため、直接&lt;code&gt;npx&lt;&#x2F;code&gt;で実行するのでなく、シェルを指定したシェルスクリプトを作成しそれを実行させるように修正しました。
以下は&lt;code&gt;~&#x2F;bin&#x2F;inkdrop-mcp&lt;&#x2F;code&gt;などの名前で作成してください&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-2-1&quot;&gt;&lt;a href=&quot;#fn-2&quot;&gt;1&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-shebang z-shell z-meta z-shebang z-shell&quot;&gt;#!&#x2F;usr&#x2F;bin&#x2F;env fish&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# fish版のMCPスクリプト&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;npx&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; -y @inkdropapp&#x2F;mcp-server&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;1行目の&lt;code&gt;fish&lt;&#x2F;code&gt;の部分は自身の環境に合わせて修正してください。&lt;&#x2F;p&gt;
&lt;p&gt;実行権限をつけておきます。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;chmod&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; +x ~&#x2F;bin&#x2F;inkdrop-mcp&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;Claude_Desktopの設定&quot;&gt;Claude Desktopの設定&lt;&#x2F;h2&gt;
&lt;p&gt;設定したInkdropのサーバーの設定をClaude Desktopに追加します。Claude Desktopの設定画面を開くと下記のようになっています。&lt;&#x2F;p&gt;
&lt;!-- textlint-disable --&gt;
&lt;img
  src=&quot;https:&amp;#x2F;&amp;#x2F;codedchords.dev&amp;#x2F;blog&amp;#x2F;2025&amp;#x2F;03&amp;#x2F;claude-integration-with-inkdrop&amp;#x2F;setup-claude.webp?h=df5178f141a430c0eb04&quot;
  alt=&quot;Setting画面&quot; width=&quot;904&quot; height=&quot;672&quot; loading=&quot;lazy&quot;
&#x2F;&gt;&lt;!-- textlint-enable --&gt;
&lt;p&gt;この画面で「構成を編集」というボタンを押すと、Finderが起動して設定ファイルを示してくれます。このボタンを押さなくても、ターミナルから&lt;code&gt;~&#x2F;Library&#x2F;Application Support&#x2F;Claude&#x2F;claude_desktop_config.json&lt;&#x2F;code&gt;を開いて編集しても大丈夫です。&lt;&#x2F;p&gt;
&lt;p&gt;次のような設定を追加します。&lt;code&gt;command&lt;&#x2F;code&gt;の設定は先ほど作成したシェルスクリプトを絶対パスで指定します。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;json&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;  &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;mcpServers&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;: {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;inkdrop&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;: {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;      &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;command&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;&#x2F;Users&#x2F;foo&#x2F;bin&#x2F;inkdrop-mcp&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;      &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;args&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;: [],&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;      &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;env&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;: {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;        &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;INKDROP_LOCAL_SERVER_URL&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;http:&#x2F;&#x2F;localhost:19840&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;        &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;INKDROP_LOCAL_USERNAME&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;foo&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;        &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;INKDROP_LOCAL_PASSWORD&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;bar&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;      }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;  }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;編集後、Claude Desktopを再起動して設定画面を確認すると。&lt;code&gt;inkdrop&lt;&#x2F;code&gt;という設定が追加されているはずです。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;Inkdrop&#x2F;Claude統合を試してみる&quot;&gt;Inkdrop&#x2F;Claude統合を試してみる&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;MCP統合で何ができるか？&quot;&gt;MCP統合で何ができるか？&lt;&#x2F;h3&gt;
&lt;p&gt;MCP統合で何ができるかは、&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;inkdropapp&#x2F;mcp-server?ref=devas.life#&quot;&gt;inkdrop&#x2F;mcp-server&lt;&#x2F;a&gt;のREADME.mdを見ると何となく分かってきます。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;Subheading&gt;Inkdrop MCPサーバーのComponents&lt;&#x2F;Subheading&gt;&lt;&#x2F;p&gt;
&lt;dl&gt;
  &lt;dt&gt;`read-note`&lt;&#x2F;dt&gt;
  &lt;dd&gt;Noteの参照&lt;&#x2F;dd&gt;
  &lt;dt&gt;`search-notes`&lt;&#x2F;dt&gt;
  &lt;dd&gt;キーワードでのNoteの検索&lt;&#x2F;dd&gt;
  &lt;dt&gt;`list-notes`&lt;&#x2F;dt&gt;
  &lt;dd&gt; Notebookを指定してのNoteのリスト&lt;&#x2F;dd&gt;
  &lt;dt&gt;`create-note`&lt;&#x2F;dt&gt;{&quot; &quot;}
  &lt;dd&gt;Noteの作成 &lt;&#x2F;dd&gt;
  &lt;dt&gt;`update-note`&lt;&#x2F;dt&gt;{&quot; &quot;}
  &lt;dd&gt;既存の Noteの更新 &lt;&#x2F;dd&gt;
  &lt;dt&gt;`list-notebooks`&lt;&#x2F;dt&gt;{&quot; &quot;}
  &lt;dd&gt;Notebookのリスト &lt;&#x2F;dd&gt;
  &lt;dt&gt;`list-tags`&lt;&#x2F;dt&gt;{&quot; &quot;}
  &lt;dd&gt;タグのリスト &lt;&#x2F;dd&gt;
&lt;&#x2F;dl&gt;
&lt;h3 id=&quot;実際に試してみる&quot;&gt;実際に試してみる&lt;&#x2F;h3&gt;
&lt;p&gt;この記事はInkdropでドラフトを執筆していますが、ここまで書いた時点でClaudeにInkdrop&#x2F;Claude統合の方法を聞いてみました。
敢えて英語で聞いてみました。途中MCPの使用を許可するかというダイアログが出てくるので、「このチャットで許可」を押します。&lt;&#x2F;p&gt;
&lt;!-- textlint-disable --&gt;
&lt;img
  src=&quot;https:&amp;#x2F;&amp;#x2F;codedchords.dev&amp;#x2F;blog&amp;#x2F;2025&amp;#x2F;03&amp;#x2F;claude-integration-with-inkdrop&amp;#x2F;dialog-claude.webp?h=15d5e114b73bf62979cb&quot;
  alt=&quot;確認画面&quot; width=&quot;1112&quot; height=&quot;912&quot; loading=&quot;lazy&quot;
&#x2F;&gt;&lt;!-- textlint-enable --&gt;
&lt;p&gt;何度かダイアログが表示されますが、同様に許可していくと次のように表示されました。英語ですが、きちんとまとめられてます。&lt;&#x2F;p&gt;
&lt;!-- textlint-disable --&gt;
&lt;img
  src=&quot;https:&amp;#x2F;&amp;#x2F;codedchords.dev&amp;#x2F;blog&amp;#x2F;2025&amp;#x2F;03&amp;#x2F;claude-integration-with-inkdrop&amp;#x2F;exampe-claude.webp?h=ea0bcdacaea552d3b212&quot;
  alt=&quot;結果画面&quot; width=&quot;1101&quot; height=&quot;1081&quot; loading=&quot;lazy&quot;
&#x2F;&gt;&lt;!-- textlint-enable --&gt;
&lt;h2 id=&quot;まとめ&quot;&gt;まとめ&lt;&#x2F;h2&gt;
&lt;p&gt;Inkdrop内の自身のドキュメントがClaudeで活用できるのは思った以上に便利ですし、
Inkdropに知見をまとめていく行為もより価値を出せるようになります。&lt;&#x2F;p&gt;
&lt;p&gt;プロジェクトでClaude Codeを利用すると、プロジェクト内のコードをClaude Codeが
見渡してくれるので生産性が飛躍的に向上しますが、同じことをドキュメンテーショ
ンでもInkdropとの組み合わせで実現できます。&lt;&#x2F;p&gt;
&lt;p&gt;実際この記事の「メリットとユースケース」の章はClaudeにドラフトさせて、
Inkdropに追記させたものをもとに微調整しただけです。&lt;&#x2F;p&gt;
&lt;p&gt;しかもClaude Codeはものすごい勢いでAnthoropicのAPIの課金を消費していきます
が、こちらはClaude Desktopを利用するのでProプランを使っていれば特にそれ以上
費用は必要ありません。&lt;&#x2F;p&gt;
&lt;p&gt;Claude周りは最近楽しいな。&lt;&#x2F;p&gt;
&lt;section class=&quot;footnotes&quot;&gt;
&lt;ol class=&quot;footnotes-list&quot;&gt;
&lt;li id=&quot;fn-2&quot;&gt;
&lt;p&gt;シェルスクリプトを作成するのでなく、Claudeでの指定で、npxをフルパスで
指定する方法もあります。お好みで。 &lt;a href=&quot;#fr-2-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;&#x2F;section&gt;
</content>
        <summary type="html">Inkdropの作者の方が、InkdropとClaudeのMCP統合についてYoutubeを上げていたので、早速検証しましたが、自分の書きためたKnowledgeをClaudeで活用できることがこんなに便利かと驚きました。</summary>
        </entry><entry xml:lang="en">
        <title>Next.jsでsitemap.xmlとrobots.txtを実装する</title>
        <published>2025-03-25T00:00:00+00:00</published>
        <updated>2025-03-25T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2025/03/creating-sitemap/" type="text/html"/>
        <id>https://codedchords.dev/blog/2025/03/creating-sitemap/</id>
        
            <content type="html">&lt;p&gt;ウェブサイトを検索エンジンに正しくインデックスしてもらうためには、&lt;code&gt;sitemap.xml&lt;&#x2F;code&gt;と&lt;code&gt;robots.txt&lt;&#x2F;code&gt;の適切な実装が不可欠です。
このブログではNext.jsのApp Routerを使用して、これらのファイルを動的に生成するよう実装しました。&lt;&#x2F;p&gt;
&lt;p&gt;この記事では、その実装方法とSEOの観点からの注意点を説明します。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;1._sitemap.xml_実装を実装する&quot;&gt;1. sitemap.xml 実装を実装する&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;1.1._sitemap.xmlとは&quot;&gt;1.1. sitemap.xmlとは&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;code&gt;sitemap.xml&lt;&#x2F;code&gt;は、ウェブサイト内の各ページのURLや更新頻度、優先度などの情報をまとめたXMLファイルです。
これにより、検索エンジンのクローラーがサイト構造を理解しやすくなり、効率的なインデックス作成が可能になります。&lt;&#x2F;p&gt;
&lt;p&gt;主な要素は以下の通りです。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;loc&amp;gt;&lt;&#x2F;code&gt; - ページのURL&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;lastmod&amp;gt;&lt;&#x2F;code&gt; - 最終更新日&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;changefreq&amp;gt;&lt;&#x2F;code&gt; - 更新頻度&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;priority&amp;gt;&lt;&#x2F;code&gt; - 重要度&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;1.2._sitemap.xml_の実装例&quot;&gt;1.2. sitemap.xml の実装例&lt;&#x2F;h3&gt;
&lt;p&gt;Next.jsのApp Routerでは、ルートハンドラーを使用して動的にsitemap.xmlを生成できます。
以下はこのブログでの実装例です。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;typescript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;&#x2F;&#x2F; src&#x2F;app&#x2F;sitemap.xml&#x2F;route.ts&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-storage z-modifier z-storage z-type&quot;&gt;export async function&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; GET&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;() {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;  const&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt; siteUrl&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; process&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;env&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-constant&quot;&gt;NEXT_PUBLIC_SITE_URL&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;  if&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; (&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;!&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-source&quot;&gt;siteUrl)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;    throw&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; Error&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;Missing NEXT_PUBLIC_SITE_URL environment variable&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;  }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;  &#x2F;&#x2F; 記事のIDを取得する関数&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;  function&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; getArticleIds&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;() {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;    const&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt; articlesDir&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; path&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;join&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(process&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;cwd&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;()&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;src&#x2F;app&#x2F;articles&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;    function&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; scanDir&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt;dir&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-primitive&quot;&gt; string&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt; baseDir&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;quot;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;      let&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt; results&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-primitive&quot;&gt; string&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type&quot;&gt;[]&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; []&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;      const&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt; entries&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; fs&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;readdirSync&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-variable z-other z-readwrite&quot;&gt;(dir&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;, {&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; withFileTypes&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language z-boolean&quot;&gt; true&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; }&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;      for&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; (&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;const&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt; entry&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-expression z-of z-ts&quot;&gt; of&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-source&quot;&gt; entries)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;        const&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt; fullPath&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; path&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;join&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-variable z-other z-readwrite&quot;&gt;(dir&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; entry&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-property z-ts z-source&quot;&gt;name)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;        const&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt; relativePath&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; path&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;join&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-variable z-other z-readwrite&quot;&gt;(baseDir&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; entry&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-property z-ts z-source&quot;&gt;name)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;        if&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; (entry&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;isDirectory&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;())&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt;          results&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;...&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt;results&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; ...&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;scanDir&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-variable z-other z-readwrite&quot;&gt;(fullPath&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-source&quot;&gt; relativePath)]&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;        }&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; else if&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; (entry&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-property z-ts&quot;&gt;name&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; ===&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;page.mdx&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;          results&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;push&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-variable z-other z-readwrite&quot;&gt;(baseDir)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;        }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;      }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;      return&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt; results&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;    return&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; scanDir&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-variable z-other z-readwrite&quot;&gt;(articlesDir)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;  }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;  const&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt; articleIds&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; getArticleIds&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;()&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;  &#x2F;&#x2F; 最新の記事の日付を取得する関数&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;  function&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; getLatestArticleDate&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;() {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;    let&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt; latestDate&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-new&quot;&gt; new&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; Date&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;0&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt; &#x2F;&#x2F; 1970-01-01&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;    for&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; (&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;const&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt; id&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-expression z-of z-ts&quot;&gt; of&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-source&quot;&gt; articleIds)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;      try&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;        &#x2F;&#x2F; ファイルから直接コンテンツを読み込む&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;        const&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt; mdxPath&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; path&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;join&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;          process&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;cwd&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;()&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;          &amp;quot;src&#x2F;app&#x2F;articles&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt;          id&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;          &amp;quot;page.mdx&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;        )&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;        const&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt; mdxContent&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; fs&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;readFileSync&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-variable z-other z-readwrite&quot;&gt;(mdxPath&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;utf-8&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;        &#x2F;&#x2F; 日付を抽出&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;        const&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt; dateMatch&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; mdxContent&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;match&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin&quot;&gt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-regexp z-ts&quot;&gt;date:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-character-class z-regexp&quot;&gt;\s&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-quantifier z-regexp&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-character-class z-regexp&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-regexp z-ts&quot;&gt;&amp;quot;&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-character-class z-regexp&quot;&gt;]&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-group z-regexp&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-character-class z-regexp&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-quantifier z-regexp&quot;&gt;+?&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-group z-regexp&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-character-class z-regexp&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-regexp z-ts&quot;&gt;&amp;quot;&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-character-class z-regexp&quot;&gt;]&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end&quot;&gt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;        if&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-variable z-other z-readwrite&quot;&gt; (dateMatch)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;          const&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt; extractedDate&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-new&quot;&gt; new&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; Date&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-variable z-other z-readwrite&quot;&gt;(dateMatch[&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;1&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;])&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;          &#x2F;&#x2F; 有効な日付かつ最新の場合は更新&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;          if&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; (&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;!&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;isNaN&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(extractedDate&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;getTime&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;())&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; &amp;amp;&amp;amp;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt; extractedDate&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; &amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-source&quot;&gt; latestDate)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt;            latestDate&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt; extractedDate&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;          }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;        }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;      }&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; catch&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-variable z-other z-readwrite&quot;&gt; (error)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;        console&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;error&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;          `Error processing article &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;${&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt;id&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt; for date extraction:`&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt;          error&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;        )&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;      }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;    &#x2F;&#x2F; ISO形式の日付を返す（例: 2025-03-25）&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;    return&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; latestDate&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;toISOString&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;()&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;split&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;T&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;)[&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;0&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;]&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;  }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;  &#x2F;&#x2F; 最新記事の日付を取得&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;  const&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt; latestArticleDate&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; getLatestArticleDate&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;()&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;  &#x2F;&#x2F; 静的ページのURL、changefreq、priority 設定&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;  const&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt; staticPages&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; [&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;      url&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;quot;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;      changefreq&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;daily&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;      priority&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;1.0&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;      lastmod&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt; latestArticleDate&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    },&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt; &#x2F;&#x2F; ホームページ&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    {&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; url&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;&#x2F;about&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; changefreq&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;monthly&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; priority&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;0.5&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; },&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;      url&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;&#x2F;articles&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;      changefreq&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;daily&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;      priority&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;0.9&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;      lastmod&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt; latestArticleDate&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    },&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt; &#x2F;&#x2F; 記事一覧ページには最新記事の日付&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    {&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; url&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;&#x2F;whisper&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; changefreq&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;daily&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; priority&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;0.4&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; },&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    {&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; url&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;&#x2F;uses&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; changefreq&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;monthly&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; priority&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;0.7&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; },&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    {&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; url&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;&#x2F;music&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; changefreq&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;monthly&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; priority&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;0.5&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; },&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;  ]&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;  &#x2F;&#x2F; サイトマップXMLの作成&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;  let&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt; sitemap&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; `&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot;?&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;&amp;lt;urlset xmlns=&amp;quot;http:&#x2F;&#x2F;www.sitemaps.org&#x2F;schemas&#x2F;sitemap&#x2F;0.9&amp;quot;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;`&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;  &#x2F;&#x2F; 静的ページをサイトマップに追加&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;  for&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; (&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;const&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt; page&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-expression z-of z-ts&quot;&gt; of&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-source&quot;&gt; staticPages)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt;    sitemap&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; +=&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; `  &amp;lt;url&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;    &amp;lt;loc&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;${&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt;siteUrl&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;}${&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt;page&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-property z-ts&quot;&gt;url&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&amp;lt;&#x2F;loc&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    ${&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt;page&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-property z-ts&quot;&gt;lastmod&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; ?&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; `&amp;lt;lastmod&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;${&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt;page&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-property z-ts&quot;&gt;lastmod&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt;&amp;lt;&#x2F;lastmod&amp;gt;`&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; :&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;quot;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;    &amp;lt;changefreq&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;${&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt;page&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-property z-ts&quot;&gt;changefreq&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&amp;lt;&#x2F;changefreq&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;    &amp;lt;priority&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;${&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt;page&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-property z-ts&quot;&gt;priority&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&amp;lt;&#x2F;priority&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;  &amp;lt;&#x2F;url&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;`&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;  }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;  &#x2F;&#x2F; 記事ページをサイトマップに追加&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;  for&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; (&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;const&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt; id&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-expression z-of z-ts&quot;&gt; of&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-source&quot;&gt; articleIds)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;    try&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;      &#x2F;&#x2F; ファイルから直接コンテンツを読み込む&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;      const&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt; mdxPath&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; path&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;join&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;        process&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;cwd&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;()&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;        &amp;quot;src&#x2F;app&#x2F;articles&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt;        id&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;        &amp;quot;page.mdx&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;      )&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;      const&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt; mdxContent&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; fs&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;readFileSync&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-variable z-other z-readwrite&quot;&gt;(mdxPath&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;utf-8&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;      &#x2F;&#x2F; 日付を抽出&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;      const&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt; dateMatch&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; mdxContent&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;match&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin&quot;&gt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-regexp z-ts&quot;&gt;date:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-character-class z-regexp&quot;&gt;\s&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-quantifier z-regexp&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-character-class z-regexp&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-regexp z-ts&quot;&gt;&amp;quot;&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-character-class z-regexp&quot;&gt;]&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-group z-regexp&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-character-class z-regexp&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-quantifier z-regexp&quot;&gt;+?&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-group z-regexp&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-character-class z-regexp&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-regexp z-ts&quot;&gt;&amp;quot;&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-character-class z-regexp&quot;&gt;]&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end&quot;&gt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;      let&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt; date&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-new&quot;&gt; new&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; Date&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;()&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;toISOString&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;()&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;split&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;T&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;)[&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;0&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;]&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;      if&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-variable z-other z-readwrite&quot;&gt; (dateMatch)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;        const&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt; extractedDate&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-new&quot;&gt; new&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; Date&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-variable z-other z-readwrite&quot;&gt;(dateMatch[&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;1&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;])&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;        &#x2F;&#x2F; 有効な日付の場合のみ使用&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;        if&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; (&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;!&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;isNaN&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(extractedDate&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;getTime&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;()))&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt;          date&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; extractedDate&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;toISOString&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;()&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;split&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;T&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;)[&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;0&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;]&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;        }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;      }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;      const&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt; articleUrl&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; `&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;${&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt;siteUrl&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&#x2F;articles&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;${&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt;id&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;`&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt;      sitemap&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; +=&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; `  &amp;lt;url&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;    &amp;lt;loc&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;${&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt;articleUrl&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&amp;lt;&#x2F;loc&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;    &amp;lt;lastmod&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;${&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt;date&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&amp;lt;&#x2F;lastmod&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;    &amp;lt;changefreq&amp;gt;monthly&amp;lt;&#x2F;changefreq&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;    &amp;lt;priority&amp;gt;1.0&amp;lt;&#x2F;priority&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;  &amp;lt;&#x2F;url&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;`&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    }&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; catch&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-variable z-other z-readwrite&quot;&gt; (error)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;      console&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;error&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;`Error processing article &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;${&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt;id&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt; for sitemap:`&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-source&quot;&gt; error)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;  }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;  &#x2F;&#x2F; サイトマップを閉じる&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt;  sitemap&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; +=&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; `&amp;lt;&#x2F;urlset&amp;gt;`&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;  return&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-new&quot;&gt; new&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; Response&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-variable z-other z-readwrite&quot;&gt;(sitemap&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;, {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    status&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 200&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    headers&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;      &amp;quot;content-type&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;application&#x2F;xml&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;      &amp;quot;cache-control&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;s-maxage=86400&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    },&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;  }&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;この実装では以下のポイントに注目しています。&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;記事の動的探索&lt;&#x2F;strong&gt;: &lt;code&gt;getArticleIds()&lt;&#x2F;code&gt;関数を使用して、articlesディレクトリ内のすべてのMDXファイルを再帰的に探索&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;最新記事日付の検出&lt;&#x2F;strong&gt;: &lt;code&gt;getLatestArticleDate()&lt;&#x2F;code&gt;関数で、全記事から最新の記事日付を取得&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;記事以外の設定&lt;&#x2F;strong&gt;: 記事以外はパスが固定なので予め配列にパスと更新頻度を設定&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;更新頻度と重要度の最適化&lt;&#x2F;strong&gt;: 各ページタイプに適した&lt;code&gt;changefreq&lt;&#x2F;code&gt;と&lt;code&gt;priority&lt;&#x2F;code&gt;の値を設定
&lt;ul&gt;
&lt;li&gt;個別記事ページ: &lt;code&gt;changefreq:monthly&lt;&#x2F;code&gt; と &lt;code&gt;priority: 1.0&lt;&#x2F;code&gt;で固定&lt;&#x2F;li&gt;
&lt;li&gt;その他のページ: 配列でページの特性に応じて設定&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;ホームと記事一覧に最新日付を適用&lt;&#x2F;strong&gt;: トップページと記事一覧ページには最新記事の日付を&lt;code&gt;lastmod&lt;&#x2F;code&gt;として使用し、これらのページが最新コンテンツを反映していることを検索エンジンに伝える&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;柔軟な構造&lt;&#x2F;strong&gt;: &lt;code&gt;page.lastmod&lt;&#x2F;code&gt;が存在する場合のみ&lt;code&gt;&amp;lt;lastmod&amp;gt;&lt;&#x2F;code&gt;タグを出力する条件付きレンダリング&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;キャッシュ設定&lt;&#x2F;strong&gt;: &lt;code&gt;cache-control&lt;&#x2F;code&gt;ヘッダーで24時間のキャッシュを設定&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;h3 id=&quot;1.3._changefreq_の適切な設定&quot;&gt;1.3. changefreq の適切な設定&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;code&gt;changefreq&lt;&#x2F;code&gt;値は検索エンジンへのヒントであり、実際のクロール頻度を保証するものではありません。
一般的な設定の目安。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;always&lt;&#x2F;code&gt;: 常に変化するページ（リアルタイムデータ表示など）&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;hourly&lt;&#x2F;code&gt;: 1時間単位で更新（ニュースページなど）&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;daily&lt;&#x2F;code&gt;: 毎日更新（ブログトップ、記事一覧など）&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;weekly&lt;&#x2F;code&gt;: 週単位で更新（プロジェクトページなど）&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;monthly&lt;&#x2F;code&gt;: 月単位で更新（Aboutページなど）&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;yearly&lt;&#x2F;code&gt;: 年単位で更新（利用規約など）&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;never&lt;&#x2F;code&gt;: 更新されないページ（アーカイブなど）&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;ページの実際の更新パターンに合わせた設定が望ましいですが、最終的なクロール頻度は検索エンジンのアルゴリズムが決定します。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;1.4._lastmod_の意義と適切な設定&quot;&gt;1.4. lastmod の意義と適切な設定&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;code&gt;lastmod&lt;&#x2F;code&gt;はページの最終更新日を示し、以下の点で重要です。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;クローラーの効率化&lt;&#x2F;strong&gt;: 検索エンジンは最近変更されたページを優先的に再クロールできる&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;インデックス更新の促進&lt;&#x2F;strong&gt;: 新しいコンテンツや変更を素早くインデックスに反映&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;鮮度シグナル&lt;&#x2F;strong&gt;: コンテンツの最新性を伝えるシグナルとなる可能性がある&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;今回の実装では以下のアプローチを取っています。&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;個別記事&lt;&#x2F;strong&gt;: 記事のfrontmatterから日付を抽出して使用&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;ホームページと記事一覧&lt;&#x2F;strong&gt;: すべての記事から最新の日付を取得し反映（最新のコンテンツへのリンクを含むため）&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;その他のページ&lt;&#x2F;strong&gt;: 明示的に指定しない（検索エンジンが自動判断）&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;この方法により、各ページが適切な最終更新日を持ち、検索エンジンが最新のコンテンツを効率的に処理できるようになります。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;2._robots.txt_を実装する&quot;&gt;2. robots.txt を実装する&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;code&gt;robots.txt&lt;&#x2F;code&gt;はクローラーに対するルールを記述したファイルで、同様にルートハンドラーで実装できます。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;typescript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;&#x2F;&#x2F; src&#x2F;app&#x2F;robots.txt&#x2F;route.ts&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-storage z-modifier z-storage z-type&quot;&gt;export async function&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; GET&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;() {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;  const&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt; siteUrl&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; process&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;env&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-constant&quot;&gt;NEXT_PUBLIC_SITE_URL&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;  if&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; (&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;!&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-source&quot;&gt;siteUrl)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;    throw&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; Error&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;Missing NEXT_PUBLIC_SITE_URL environment variable&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;  }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;  const&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt; robotsTxt&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; `# https:&#x2F;&#x2F;www.robotstxt.org&#x2F;robotstxt.html&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;User-agent: *&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;Allow: &#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;# Sitemaps&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;Sitemap: &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;${&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt;siteUrl&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&#x2F;sitemap.xml&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;`&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;  return&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-new&quot;&gt; new&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; Response&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-variable z-other z-readwrite&quot;&gt;(robotsTxt&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;, {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    status&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 200&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    headers&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;      &amp;quot;content-type&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;text&#x2F;plain&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;      &amp;quot;cache-control&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;s-maxage=86400&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    },&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;  }&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;この実装ではすべてのロボットにサイト全体へのアクセスを許可し、sitemap.xmlの場所を明示しています。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;2.1._robots.txt実装上の注意点&quot;&gt;2.1. robots.txt実装上の注意点&lt;&#x2F;h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;環境変数の設定&lt;&#x2F;strong&gt;: &lt;code&gt;NEXT_PUBLIC_SITE_URL&lt;&#x2F;code&gt;を必ず設定する&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;キャッシュの検討&lt;&#x2F;strong&gt;: 頻繁に記事を追加する場合は、キャッシュ期間を短くする(個人のブログサイトなので現在の24時間で十分)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;エラーハンドリング&lt;&#x2F;strong&gt;: 記事読み込みエラーが全体に影響しないようtry-catchで処理&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;検証&lt;&#x2F;strong&gt;: &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;search.google.com&#x2F;search-console&quot;&gt;Google Search Console&lt;&#x2F;a&gt;でサイトマップを登録し、エラーがないか確認する&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;h2 id=&quot;3._まとめ&quot;&gt;3. まとめ&lt;&#x2F;h2&gt;
&lt;p&gt;適切な&lt;code&gt;sitemap.xml&lt;&#x2F;code&gt;と&lt;code&gt;robots.txt&lt;&#x2F;code&gt;の実装はSEOの基本です。Next.jsのApp Routerを使うと、これらのファイルを動的に生成できるため、コンテンツの増加に合わせて自動的に更新されるサイトマップを維持できます。&lt;&#x2F;p&gt;
&lt;p&gt;更新頻度や優先度の設定は、サイトのコンテンツ特性を考慮して決定しましょう。最終的には検索エンジンのアルゴリズムが実際のクロール頻度を決定しますが、適切なヒントを提供することで、より効率的なインデックス作成を促進できます。&lt;&#x2F;p&gt;
</content>
        <summary type="html">うっかり実装を忘れていたsitemap.xmlとrobots.txtをNext.jsのApp Routerを使用して実装しました。合わせて、検索エンジン最適化のためのベストプラクティスもまとめています。</summary>
        </entry><entry xml:lang="en">
        <title>ヘッドレスCMS Contentfulを活用したつぶやき機能の実装</title>
        <published>2025-03-24T00:00:00+00:00</published>
        <updated>2025-03-24T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2025/03/contentful/" type="text/html"/>
        <id>https://codedchords.dev/blog/2025/03/contentful/</id>
        
            <content type="html">&lt;h2 id=&quot;Contentfulとは&quot;&gt;Contentfulとは&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.contentful.com&#x2F;&quot;&gt;Contentful&lt;&#x2F;a&gt;は、ヘッドレスCMSのひとつで、コンテンツ管理とAPI配信に特化したサー
ビスです。ウェブサイトやアプリ向けのコンテンツを一元管理し、RESTful APIや
GraphQL APIを通じて、あらゆるデバイスやプラットフォームに配信できます。&lt;&#x2F;p&gt;
&lt;p&gt;構造化されたコンテンツモデルを定義でき、マークダウンやリッチテキストエディタを備
え、多言語対応も可能です。開発者はフロントエンドを自由に構築でき、コンテンツ
編集者は直感的なインターフェースでコンテンツを管理できます。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;「つぶやき」機能を作ってみる&quot;&gt;「つぶやき」機能を作ってみる&lt;&#x2F;h2&gt;
&lt;p&gt;ブログにContentfulを使って「つぶやき」機能をつけてみましょう。&lt;&#x2F;p&gt;
&lt;p&gt;「つぶやき」コンテンツ自体はContentfulで管理します。
今回つぶやき投稿についてはContentfulのデフォルトのエディタを使用し、
特にコンテンツ作成用のアプリを作成しないことにします。&lt;&#x2F;p&gt;
&lt;p&gt;このブログの「つぶやき機能」ではContentfulからRESTful APIを使って読み出し、
時系列で表示するものとします。Paginationも入れましょう。&lt;&#x2F;p&gt;
&lt;p&gt;以下が実現イメージです。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;ContentfulでのContent_Modelの定義&quot;&gt;ContentfulでのContent Modelの定義&lt;&#x2F;h2&gt;
&lt;p&gt;ContentfulではまずSpaceを作ることになりますが、今回は無料枠を利用する予定な
ので、デフォルトのSpace &lt;code&gt;Blank&lt;&#x2F;code&gt;を使います。&lt;&#x2F;p&gt;
&lt;p&gt;次に&lt;strong&gt;Content Model&lt;&#x2F;strong&gt;を作成します。今回は &lt;code&gt;whisper&lt;&#x2F;code&gt;と名付けました。
シンプルに以下のようにしました。idは現時点では不要ですが、将来編集アプリを作
る時に備えて一応用意しました。&lt;&#x2F;p&gt;
&lt;!-- textlint-disable --&gt;
&lt;img
  src=&quot;https:&amp;#x2F;&amp;#x2F;codedchords.dev&amp;#x2F;blog&amp;#x2F;2025&amp;#x2F;03&amp;#x2F;contentful&amp;#x2F;content-model.webp?h=792dde0896adc5c8ff31&quot;
  alt=&quot;Content Model&quot; width=&quot;981&quot; height=&quot;292&quot; loading=&quot;lazy&quot;
&#x2F;&gt;&lt;!-- textlint-enable --&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Name&lt;&#x2F;th&gt;&lt;th&gt;Field ID&lt;&#x2F;th&gt;&lt;th&gt;Attribute&lt;&#x2F;th&gt;&lt;th&gt;Unique&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;id&lt;&#x2F;td&gt;&lt;td&gt;id&lt;&#x2F;td&gt;&lt;td&gt;Decimal&lt;&#x2F;td&gt;&lt;td&gt;Y&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;whisper_time&lt;&#x2F;td&gt;&lt;td&gt;whisperTime&lt;&#x2F;td&gt;&lt;td&gt;Date &amp;amp; time&lt;&#x2F;td&gt;&lt;td&gt;N&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;whisper&lt;&#x2F;td&gt;&lt;td&gt;whisper&lt;&#x2F;td&gt;&lt;td&gt;Short text&lt;&#x2F;td&gt;&lt;td&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;location&lt;&#x2F;td&gt;&lt;td&gt;location&lt;&#x2F;td&gt;&lt;td&gt;Location&lt;&#x2F;td&gt;&lt;td&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;h2 id=&quot;Contentfulからのつぶやきの読み出し&quot;&gt;Contentfulからのつぶやきの読み出し&lt;&#x2F;h2&gt;
&lt;p&gt;Contentfulからのコンテンツの読み出しには、ContentfulのSDKを使用しています。&lt;&#x2F;p&gt;
&lt;p&gt;基本的な読み出しは以下のようなコードになります。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;typescript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;const&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt; contentful&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; require&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;contentful&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;const&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-constant z-ts&quot;&gt; client&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; contentful&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;createClient&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;  space&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;@@@@@@@&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;  environment&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;master&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt; &#x2F;&#x2F; defaults to &amp;#39;master&amp;#39; if not set&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;  accessToken&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt;client&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;  .&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;getEntry&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;@@@@@@@@@@@@@@@@@@@@@@@@&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;  .&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;then&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt;entry&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-function z-arrow z-ts&quot;&gt; =&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; console&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;log&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-variable z-other z-readwrite&quot;&gt;(entry))&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;  .&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;catch&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(console&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-property z-ts z-source&quot;&gt;error)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;実際には
&lt;code&gt;space&lt;&#x2F;code&gt;,
&lt;code&gt;environment&lt;&#x2F;code&gt;,&lt;code&gt;accessToken&lt;&#x2F;code&gt;などは、Amplifyのビルド設定で &lt;code&gt;.env&lt;&#x2F;code&gt;に書き込んで
環境変数から読み出しています。&lt;&#x2F;p&gt;
&lt;p&gt;Paginationについては、まず10個を上限で読み出し改ページの際にレコードの開始位置を変更して実現しています。
当初はISR &lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-2-1&quot;&gt;&lt;a href=&quot;#fn-2&quot;&gt;1&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt; で実装しましたが、Contentfulとうまく連携できずWebhookでの実装も試しました。
しかし、いずれも思ったように動作しなかったりサーバーの負荷も高いため、
クライアントコンポーネントとしてクライアント側でカーソルを管理しページ制御を
実装しました。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;Whisper実現イメージ&quot;&gt;Whisper実現イメージ&lt;&#x2F;h2&gt;
&lt;p&gt;このブログに「&lt;strong&gt;Whisper&lt;&#x2F;strong&gt;」というメニューを配置し、つぶやきを表示するように
しました。以下のようなイメージです。&lt;&#x2F;p&gt;
&lt;p&gt;Locationは緯度・軽度が記録されているので、緯度経度の表示とともに
Open Street Mapへのリンクも埋め込みました。&lt;&#x2F;p&gt;
&lt;figure&gt;
  &lt;img src=&quot;whisper.webp&quot; alt=&quot;Whisper実現イメージ&quot; &#x2F;&gt;
  &lt;figcaption&gt;Whisper 実現イメージ&lt;&#x2F;figcaption&gt;
&lt;&#x2F;figure&gt;
&lt;h2 id=&quot;まとめ&quot;&gt;まとめ&lt;&#x2F;h2&gt;
&lt;p&gt;今回は非常に簡単な実装でしたが、Paginationの部分でAmplifyとの互換性の問題で
苦労しました。Contentfulを使うとコンテンツ管理はContentfulに任せてしまえる
ヘッドレスCMSのメリットは体感できました。&lt;&#x2F;p&gt;
&lt;p&gt;次のようなメリットがあります。&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;フロントエンドの自由度&lt;&#x2F;strong&gt;：表示を司るフロントエンドとコンテンツ管理が分離されているため、任意の技術スタックでフロントエンドを構築可能&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;オムニチャネル対応&lt;&#x2F;strong&gt;：一度作成したコンテンツをウェブ、モバイル、IoTなど複数のプラットフォームに配信可能&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;開発の効率化&lt;&#x2F;strong&gt;：フロントエンドとバックエンドの開発を並行して進められる&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;パフォーマンス向上&lt;&#x2F;strong&gt;：静的サイト生成やCDN配信との相性が良く、高速なサイト表示が可能&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;スケーラビリティ&lt;&#x2F;strong&gt;：トラフィック増加にも柔軟に対応できる&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;セキュリティ強化&lt;&#x2F;strong&gt;：管理画面とフロントエンドが分離されているため攻撃対象が減少&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;将来性&lt;&#x2F;strong&gt;：新しいデバイスやプラットフォームにもフロントエンドだけ独立し
ているため柔軟に対応できる&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;今回作成したWhisper機能は大した意味がありませんが、
将来的につぶやき投稿機能も別途作ろうかなと思います。&lt;&#x2F;p&gt;
&lt;section class=&quot;footnotes&quot;&gt;
&lt;ol class=&quot;footnotes-list&quot;&gt;
&lt;li id=&quot;fn-2&quot;&gt;
&lt;p&gt;Incremental Static Regenerationの略。増分静的再生成とも言われ、静的生
成（SSG）の拡張機能。事前にビルド済みの静的ページを提供しながら、revalidateパラメータにより再検証間隔を設定し
バックグラウンドで定期的に再生成する機能。 &lt;a href=&quot;#fr-2-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;&#x2F;section&gt;
</content>
        <summary type="html">このブログでは直接App Router配下に記事を書いていますが、ヘッドレスCMSを使うことも検討して諦めました。今回、ライトにつぶやき程度であればできそうかなとContentfulを使って実装してみました。</summary>
        </entry><entry xml:lang="en">
        <title>textlintで日本語ブログの品質を向上させよう</title>
        <published>2025-03-23T00:00:00+00:00</published>
        <updated>2025-03-23T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2025/03/textlint-introduction/" type="text/html"/>
        <id>https://codedchords.dev/blog/2025/03/textlint-introduction/</id>
        
            <content type="html">&lt;h2 id=&quot;textlintとは&quot;&gt;textlintとは&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;textlint.github.io&#x2F;&quot;&gt;textlint&lt;&#x2F;a&gt;は、テキスト上の問題を洗い出すための静的解析ツールです。
特に日本語のテキスト校正において優れた機能を持っており、文章のスタイル、用語の統一、表記ゆれ、誤字脱字などをチェックできます。
Markdownファイルなどの構造化されたテキストファイルに対して適用できるため、
ブログ記事や技術文書の品質を向上させるのに最適です。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;なぜtextlintを導入したのか&quot;&gt;なぜtextlintを導入したのか&lt;&#x2F;h2&gt;
&lt;p&gt;技術ブログを書く際に直面する問題は、以下のようなものがあります。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;「ですます調」と「である調」の混在&lt;&#x2F;li&gt;
&lt;li&gt;全角と半角の間のスペースの不統一&lt;&#x2F;li&gt;
&lt;li&gt;句読点や括弧の前後の余計なスペース&lt;&#x2F;li&gt;
&lt;li&gt;カタカナ語の間に中黒（・）や半角スペースがない&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;これらの問題は、読者にとって違和感を与え、プロフェッショナルさを損なう可能性があります。textlintを導入することで、これらの問題を自動的に検出し、一貫した文章スタイルを維持できるようになります。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;インストールと設定&quot;&gt;インストールと設定&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;1._必要なパッケージのインストール&quot;&gt;1. 必要なパッケージのインストール&lt;&#x2F;h3&gt;
&lt;p&gt;次のコマンドでtextlintと必要なルールをインストールします。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;npm&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; install --save-dev textlint&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;  textlint-rule-preset-ja-spacing&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;  textlint-rule-preset-ja-technical-writing&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;  textlint-rule-no-mix-dearu-desumasu&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;  textlint-filter-rule-comments&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;  textlint-filter-rule-node-types&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;  textlint-plugin-mdx&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;2._.textlintrcの設定&quot;&gt;2. &lt;code&gt;.textlintrc&lt;&#x2F;code&gt;の設定&lt;&#x2F;h3&gt;
&lt;p&gt;プロジェクトのルートディレクトリに&lt;code&gt;.textlintrc&lt;&#x2F;code&gt;ファイルを作成し、以下のように設定します。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;json&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;  &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;filters&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;: {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;comments&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language z-json&quot;&gt; true&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;node-types&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;: {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;      &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;nodeTypes&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;: [&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;jsx&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;code&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;inline-code&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;html&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;BlockQuote&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    },&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;allowlist&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;: {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;      &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;allow&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;: [&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;        &amp;quot;&#x2F;&amp;lt;blockquote[^&amp;gt;]*&amp;gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt;\\&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;s&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt;\\&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;S]*?&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt;\\&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt;&#x2F;blockquote&amp;gt;&#x2F;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;        &amp;quot;&#x2F;&amp;lt;blockquote&amp;gt;([&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt;\\&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;s&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt;\\&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;S])*?&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt;\\&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt;&#x2F;blockquote&amp;gt;&#x2F;g&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;      ]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;  },&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;  &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;plugins&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;: [&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;mdx&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;],&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;  &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;rules&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;: {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;preset-ja-spacing&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;: {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;      &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;ja-nakaguro-or-halfwidth-space-between-katakana&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language z-json&quot;&gt; true&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;      &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;ja-no-space-around-parentheses&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language z-json&quot;&gt; true&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;      &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;ja-no-space-between-full-width&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language z-json&quot;&gt; true&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;      &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;ja-space-between-half-and-full-width&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;: {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;        &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;space&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;always&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;        &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;exceptPunctuation&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language z-json&quot;&gt; true&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;      },&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;      &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;ja-space-after-exclamation&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language z-json&quot;&gt; true&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;      &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;ja-space-after-question&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language z-json&quot;&gt; true&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;      &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;ja-space-around-code&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language z-json&quot;&gt; false&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    },&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;preset-ja-technical-writing&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;: {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;      &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;sentence-length&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;: {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;        &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;max&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 200&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;      },&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;      &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;no-exclamation-question-mark&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;: {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;        &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;allowHalfWidthQuestion&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language z-json&quot;&gt; true&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;        &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;allowFullWidthQuestion&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language z-json&quot;&gt; true&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;      },&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;      &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;ja-no-weak-phrase&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language z-json&quot;&gt; false&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;      &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;max-kanji-continuous-len&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;: {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;        &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;max&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 20&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;      },&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;      &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;ja-no-mixed-period&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;: {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;        &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;allowPeriodMarks&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;: [&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;箇条書き&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;リスト&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;。&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;、&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;」&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;],&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;        &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;forceAppendPeriod&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language z-json&quot;&gt; false&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;        &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;checkBlockQuote&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language z-json&quot;&gt; false&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;        &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;checkListItem&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language z-json&quot;&gt; false&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;        &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;allowExceptionContext&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language z-json&quot;&gt; true&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;        &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;ignorePeriodInQuotation&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language z-json&quot;&gt; true&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;      }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    },&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;no-mix-dearu-desumasu&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;: {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;      &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;preferInHeader&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;である&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;      &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;preferInBody&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;ですます&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;      &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;preferInList&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;である&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;      &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;strict&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language z-json&quot;&gt; false&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    },&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;@textlint-rule&#x2F;textlint-rule-no-invalid-control-character&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language z-json&quot;&gt; false&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;ja-technical-writing&#x2F;no-doubled-conjunction&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language z-json&quot;&gt; false&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;ja-technical-writing&#x2F;no-doubled-conjunctive-particle-ga&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language z-json&quot;&gt; false&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;  }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;3._package.jsonにスクリプトを追加&quot;&gt;3. package.jsonにスクリプトを追加&lt;&#x2F;h3&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;json&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;  &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;scripts&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;: {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;check&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;textlint &lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt;\&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;src&#x2F;app&#x2F;articles&#x2F;**&#x2F;*.mdx&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt;\&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;  }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;設定の詳細解説&quot;&gt;設定の詳細解説&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;フィルター&quot;&gt;フィルター&lt;&#x2F;h3&gt;
&lt;p&gt;MDXファイルには、本文の他にJSXコンポーネントやコードブロックが含まれています。
これらに対してtextlintのルールを適用すると誤検出が多発します。そのため、
フィルターを設定して特定の部分をチェック対象から除外しました。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;json&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;filters&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;: &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;  &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;comments&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language z-json&quot;&gt; true&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;  &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;node-types&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;: {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;nodeTypes&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;: [&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;jsx&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;code&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;inline-code&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;html&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;BlockQuote&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;  },&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;  &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;allowlist&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;: {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;allow&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;: [&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;      &amp;quot;&#x2F;&amp;lt;blockquote[^&amp;gt;]*&amp;gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt;\\&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;s&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt;\\&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;S]*?&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt;\\&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt;&#x2F;blockquote&amp;gt;&#x2F;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;      &amp;quot;&#x2F;&amp;lt;blockquote&amp;gt;([&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt;\\&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;s&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt;\\&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;S])*?&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt;\\&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt;&#x2F;blockquote&amp;gt;&#x2F;g&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    ]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;  }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;comments&lt;&#x2F;code&gt;: コメント部分をチェック対象から除外&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;node-types&lt;&#x2F;code&gt;: JSX、コードブロック、インラインコード、HTMLタグ、引用文をチェック対象から除外&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;allowlist&lt;&#x2F;code&gt;: 正規表現で指定したパターンをチェック対象から除外&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;blockquote要素内の引用文は自分の文章でなく修正しようもないため、
対象から外しています。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;ルール&quot;&gt;ルール&lt;&#x2F;h3&gt;
&lt;h4 id=&quot;1._「ですます調」と「である調」の統一_(no-mix-dearu-desumasu)&quot;&gt;1. 「ですます調」と「である調」の統一 (no-mix-dearu-desumasu)&lt;&#x2F;h4&gt;
&lt;p&gt;文体の一貫性を保つためのルールです。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;json&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;no-mix-dearu-desumasu&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;: &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;  &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;preferInHeader&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;である&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;  &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;preferInBody&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;ですます&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;  &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;preferInList&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;である&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;  &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;strict&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language z-json&quot;&gt; false&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;ul&gt;
&lt;li&gt;見出しは「である調」とする&lt;&#x2F;li&gt;
&lt;li&gt;本文は「ですます調」とする&lt;&#x2F;li&gt;
&lt;li&gt;リストは「である調」とする&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;strict: false&lt;&#x2F;code&gt;で厳密すぎるチェックを回避する&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h4 id=&quot;2._日本語の間隔に関するルール_(preset-ja-spacing)&quot;&gt;2. 日本語の間隔に関するルール (preset-ja-spacing)&lt;&#x2F;h4&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;json&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;preset-ja-spacing&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;: &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;  &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;ja-nakaguro-or-halfwidth-space-between-katakana&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language z-json&quot;&gt; true&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;  &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;ja-no-space-around-parentheses&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language z-json&quot;&gt; true&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;  &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;ja-no-space-between-full-width&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language z-json&quot;&gt; true&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;  &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;ja-space-between-half-and-full-width&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;: {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;space&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;always&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;exceptPunctuation&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language z-json&quot;&gt; true&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;  },&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;  &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;ja-space-after-exclamation&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language z-json&quot;&gt; true&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;  &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;ja-space-after-question&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language z-json&quot;&gt; true&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;  &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;ja-space-around-code&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language z-json&quot;&gt; false&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;ul&gt;
&lt;li&gt;カタカナ語の間には中黒または半角スペースを入れる規則である&lt;&#x2F;li&gt;
&lt;li&gt;括弧の前後には余分なスペースを入れない規則である&lt;&#x2F;li&gt;
&lt;li&gt;全角文字の間にはスペースを入れない規則である&lt;&#x2F;li&gt;
&lt;li&gt;半角と全角の間には常にスペースを入れる規則である（句読点は例外）&lt;&#x2F;li&gt;
&lt;li&gt;感嘆符と疑問符の後にはスペースを入れる規則である&lt;&#x2F;li&gt;
&lt;li&gt;コードの前後のスペースは不要とする規則である&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h4 id=&quot;3._技術文書向けのルール_(preset-ja-technical-writing)&quot;&gt;3. 技術文書向けのルール (preset-ja-technical-writing)&lt;&#x2F;h4&gt;
&lt;p&gt;技術文書に適した日本語表現をチェックする包括的なルールセットです。冗長な表
現、読みにくい文章構造、一文の長さなどをチェックする。以下のような設定を追加
しています。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;max-kanji-continuous-len&lt;&#x2F;code&gt;: 漢字の連続使用を20文字までに制限を緩和&lt;&#x2F;li&gt;
&lt;li&gt;助詞の重複や冗長表現、不自然なアルファベット使用などを検出する機能を含む&lt;&#x2F;li&gt;
&lt;li&gt;技術文書らしい表現をチェックし、読みやすさを向上させる&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;MDXファイルの対応と実行時の問題解決&quot;&gt;MDXファイルの対応と実行時の問題解決&lt;&#x2F;h2&gt;
&lt;p&gt;Next.jsのブログでは、多くの場合MDXファイルを使用しています。
デフォルトのtextlint設定ではMDXファイルを認識できないことがあります。
実際に&lt;code&gt;npm run check&lt;&#x2F;code&gt;を実行してみると、
以下のようなデバッグ情報が表示されました。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;No Process files that are un-support extensions: [&amp;quot;&#x2F;path&#x2F;to&#x2F;your&#x2F;blog&#x2F;src&#x2F;app&#x2F;articles&#x2F;...&#x2F;page.mdx&amp;quot;,...]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;この問題を解決するには、前述のインストール手順にあるように、&lt;code&gt;textlint-plugin-mdx&lt;&#x2F;code&gt;パッケージを追加し、&lt;code&gt;.textlintrc&lt;&#x2F;code&gt;ファイルの設定に&lt;code&gt;&quot;plugins&quot;: [&quot;mdx&quot;]&lt;&#x2F;code&gt;を追加する必要があります。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;正しく設定した後の実行結果&quot;&gt;正しく設定した後の実行結果&lt;&#x2F;h3&gt;
&lt;p&gt;正しく設定した後、&lt;code&gt;npm run check&lt;&#x2F;code&gt;を実行すると、ブログ内のMDXファイルが検査され、以下のような結果が表示されます。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;path&#x2F;to&#x2F;your&#x2F;blog&#x2F;src&#x2F;app&#x2F;articles&#x2F;...&#x2F;page.mdx&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  23:138  ✓ error  原則として、全角文字と半角文字の間にスペースを入れます。                 ja-spacing&#x2F;ja-space-between-half-and-full-width&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  27:32   error    文末が&amp;quot;。&amp;quot;で終わっていません。                                           ja-technical-writing&#x2F;ja-no-mixed-period&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  40:7    ✓ error  原則として、全角文字と半角文字の間にスペースを入れます。                 ja-spacing&#x2F;ja-space-between-half-and-full-width&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  167:15  ✓ error  かっこの外側、内側ともにスペースを入れません。                           ja-spacing&#x2F;ja-no-space-around-parentheses&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  167:41  error    箇条書き: &amp;quot;である&amp;quot;調 でなければなりません                                no-mix-dearu-desumasu&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;チェックマーク（✓）がついているエラーは自動修正可能なものです。これらを一括修正するには、以下のコマンドを実行します。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;npx&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt; textlint --fix &amp;quot;src&#x2F;app&#x2F;articles&#x2F;**&#x2F;*.mdx&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;ただし、すべてのエラーが自動修正できるわけではありません。特に文体（「ですます調」と「である調」）や文末の句点、文の長さなどに関するエラーは、意図に合わせて手動で修正する必要があります。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;CI&#x2F;CDパイプラインへの組み込み&quot;&gt;CI&#x2F;CDパイプラインへの組み込み&lt;&#x2F;h3&gt;
&lt;p&gt;品質チェックを自動化するために、GitHub Actionsなどのワークフローにtextlintを組み込むこともできます。例えば、以下のような&lt;code&gt;.github&#x2F;workflows&#x2F;textlint.yml&lt;&#x2F;code&gt;ファイルを作成することで、プルリクエスト時に自動的に文章をチェックできます。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;yaml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;name&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; Textlint&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-constant z-language z-boolean&quot;&gt;on&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;  pull_request&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;    paths&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;      -&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;src&#x2F;app&#x2F;articles&#x2F;**&#x2F;*.mdx&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;jobs&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;  textlint&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;    runs-on&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; ubuntu-latest&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;    steps&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;      -&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt; uses&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; actions&#x2F;checkout@v3&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;      -&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt; uses&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; actions&#x2F;setup-node@v3&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;        with&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;          node-version&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;20&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;          cache&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;npm&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;      -&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt; run&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; npm ci&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;      -&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt; run&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; npm run check&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;期待される効果&quot;&gt;期待される効果&lt;&#x2F;h2&gt;
&lt;p&gt;textlintを導入することで得られる主な効果は以下の通りです。&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;一貫した文体&lt;&#x2F;strong&gt;: 文体が混在しない文章になる&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;読みやすさの向上&lt;&#x2F;strong&gt;: 適切な空白や区切りにより、読みやすい文章になる&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;プロフェッショナルな印象&lt;&#x2F;strong&gt;: 表記の一貫性により、プロフェッショナルな印象を与える&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;効率的な校正&lt;&#x2F;strong&gt;: 手動での確認作業が減り、効率的に校正できる&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;品質の均一化&lt;&#x2F;strong&gt;: 複数の執筆者がいる場合でも、文章スタイルを統一できる&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;CI&#x2F;CDパイプラインとの統合&lt;&#x2F;strong&gt;: Node.jsベースのツールであるため、GitHub ActionsやJenkins、AWS CodeBuildなどのCI&#x2F;CDパイプラインに容易に組み込める&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;h2 id=&quot;まとめ&quot;&gt;まとめ&lt;&#x2F;h2&gt;
&lt;p&gt;textlintは、日本語の技術ブログを書く際の強力な味方です。
適切な設定により、文章の品質を向上させ、読者にとって読みやすく一貫性のある記事を提供できます。特にMDXを使ったブログでは、フィルター設定により、記事本文とコードやJSXを適切に区別してチェックできます。&lt;&#x2F;p&gt;
&lt;p&gt;Next.js + Tailwind Plus(旧Tailwind UI)をベースにしたブログシステムとの相性
も抜群です。Node.jsベースのツールであるため、同じエコシステム内で簡単に導入
でき、npmスクリプトとして実行できます。さらに、GitHub ActionsなどのCI&#x2F;CD
パイプラインに組み込むことで、プルリクエスト時に自動的に文章をチェックし、品
質を担保も可能です。&lt;&#x2F;p&gt;
&lt;p&gt;今回紹介した設定は、MDXファイルを使ったNext.jsブログに最適化されていますが、他の形式の文書にも応用可能です。自分の文書スタイルや好みに合わせてカスタマイズしてみてください。&lt;&#x2F;p&gt;
&lt;p&gt;定期的に&lt;code&gt;npm run check&lt;&#x2F;code&gt;を実行し、指摘された問題を修正することで、ブログ記事の品質を着実に向上させることができます。&lt;&#x2F;p&gt;
</content>
        <summary type="html">textlintを活用して日本語の技術ブログ記事の品質を向上させる方法を紹介します。特にこのブログではMarkdownでなくMDXを使用しているので、MDXファイルに対する最適な設定と導入手順を解説します。</summary>
        </entry><entry xml:lang="en">
        <title>Authorization Bypass in Next.js Middleware</title>
        <published>2025-03-22T00:00:00+00:00</published>
        <updated>2025-03-22T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2025/03/cve-2025-29927/" type="text/html"/>
        <id>https://codedchords.dev/blog/2025/03/cve-2025-29927/</id>
        
            <content type="html">&lt;h2 id=&quot;CVE情報&quot;&gt;CVE情報&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;CVE番号: CVE-2025-29927&lt;&#x2F;li&gt;
&lt;li&gt;GHSAコード: GHSA-f82v-jwr5-mffw&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;攻撃者が特定のHTTPヘッダーを操作することで、ミドルウェアの認証チェックを迂回
し、保護されたリソースにアクセスできてしまう問題のようです。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;アップデート手順&quot;&gt;アップデート手順&lt;&#x2F;h2&gt;
&lt;p&gt;アップデートの手順は次の通りです。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# Next.jsのアップデート&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;npm&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; install next@15.2.3 @next&#x2F;mdx@15.2.3 eslint-config-next@15.2.3&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# npx next updateでもいいか。&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# アップデート後問題ないか、一応Lintをかけておく&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;npm&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; run lint&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;</content>
        <summary type="html">Next.js 15.2.3未満で認証をバイパスできる脆弱性の通知がGitHubから飛んできたので、一応このブログもアップデートしました。</summary>
        </entry><entry xml:lang="en">
        <title>エンジニア的ブログ再構築 : Next.js × Tailwind Plusで得る柔軟性</title>
        <published>2025-03-17T00:00:00+00:00</published>
        <updated>2025-03-17T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2025/03/nextjs-tailwindui-blog/" type="text/html"/>
        <id>https://codedchords.dev/blog/2025/03/nextjs-tailwindui-blog/</id>
        
            <content type="html">&lt;h2 id=&quot;Micro.blogから移行&quot;&gt;Micro.blogから移行&lt;&#x2F;h2&gt;
&lt;p&gt;&quot;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;book.micro.blog&#x2F;&quot;&gt;Indie Microblogging&lt;&#x2F;a&gt;&quot;というコンセプトに共感し、
X.comのようなプラットフォームに依存せず
長文の記事だけでなくマイクロブログも可能なMicro.blog
を昨年から利用していました。
気軽なつぶやきと長文記事を同じプラットフォームで書けて、
Micro.blogのコミュニティーで海外のユーザーとのコミュニケーションも楽しくはありました。&lt;&#x2F;p&gt;
&lt;p&gt;しかし、半年くらい使ってみると次のような点で不満を持ちました。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;長文記事とつぶやきが混在するので、読みづらい。そのためテーマをカスタマイズ
して両者を分離したくなるが、よく考えると本末転倒でないかと思い始めた。Micro.blog自体も
長文を意識したSummery欄を追加したりLongformにフォーカスしたテーマが人気だったり、
コンセプトがブレてきていると感じてしまった。&lt;&#x2F;li&gt;
&lt;li&gt;やはり、Compose画面が長文には向いておらず、エディタで編集して切り貼りすることが多
く非効率。海外ユーザーはMarsEditを使っているユーザーが多いようだが、
リッチテキストを好きになれない。&lt;&#x2F;li&gt;
&lt;li&gt;Micro.blogは独自の機能とプラグインとして提供されているテーマ、バックエンドでHugo
で構成されており、それぞれの依存からカスタマイズ時の制約が大きく独自のノウハ
ウが必要となる。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;モダンな技術スタックでブログ&quot;&gt;モダンな技術スタックでブログ&lt;&#x2F;h2&gt;
&lt;p&gt;先日に遊びでNext.js + Tailwind CSSでPortfolioサイトを作りましたが、
CMSのような制約がなく、コードで部品を書いていける体験が
楽しかったのでブログも同じような技術スタックで構成することにしました。&lt;&#x2F;p&gt;
&lt;p&gt;Next.jsベースでのブログのStarter Kitのようなものはいくつか存在しますが、
興味から有償のTailwind Plusを購入したので、Tailwind Plusが提供する個人向け
Blogの&quot;Spotlight&quot;という&lt;strong&gt;Template&lt;&#x2F;strong&gt;をベースにカスタマイズしました。&lt;&#x2F;p&gt;
&lt;!-- textlint-disable --&gt;
&lt;img
  src=&quot;https:&amp;#x2F;&amp;#x2F;codedchords.dev&amp;#x2F;blog&amp;#x2F;2025&amp;#x2F;03&amp;#x2F;nextjs-tailwindui-blog&amp;#x2F;spotlight.webp?h=b31a6334b27994b8c48d&quot;
  alt=&quot;Tailwind Plus: Spotlight template&quot; width=&quot;1535&quot; height=&quot;232&quot; loading=&quot;lazy&quot;
&#x2F;&gt;&lt;!-- textlint-enable --&gt;
&lt;p&gt;Tailwind PlusのTemplateは、完全に動作するReactベースのアプリケーションコード
で、Javascript版とTypeScript版が提供されており、Tailwind CSSを利用したUI要素
だけでなく状態管理やルーティング、APIとの連携など本番環境ですぐに使用でき
る機能を全て含んでいます。next-themesを利用したダークモード対応やPrismJSを
使ったSyntax Highlight、レスポンシブ対応、画像最適化やコンポーネントのプリ
ロードなどは最初から組み込まれています。開発者はこれらのテンプレートを導入す
るだけで、最小限のカスタマイズで完全な機能を持つReactアプリケーションを短時
間で構築できると謳われています。&lt;&#x2F;p&gt;
&lt;p&gt;しかし、実際にブログで運用にはそこそこカスタマイズが必要でした。&lt;&#x2F;p&gt;
&lt;p&gt;主なカスタマイズポイントとしては以下のような点です。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;UI&#x2F;UXの改善&lt;&#x2F;strong&gt;：個人用のブログに合わせヘッダー、フッターのカスタマイズ&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;記事管理システム&lt;&#x2F;strong&gt;：App Routerの構造を活かしたシンプルなMDXベースの記事管理&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;記事一覧フィルター&lt;&#x2F;strong&gt;: 日付でのフィルター機能を追加(デフォルトではページ
制御されていないため)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;コメントシステム&lt;&#x2F;strong&gt;：Giscusを使用したGitHubベースのコメント機能&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;通常であれば、gray-matterやremarkなどを入れてヘッドレスCMSなどからMarkdown記事を取り込み
動的ルーティングで記事を生成するのが美しいのでしょうが、
「そのままMDXで書けばいいか」と割り切ってApp Routerの下に記事を書いていくスタイルにしました。
記事の執筆とサイトのコーディングの区別がつかない今のスタイルは不便もありますが、
気に入っています。HMR&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-1-1&quot;&gt;&lt;a href=&quot;#fn-1&quot;&gt;1&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;機能で特に工夫もせずに更新した記事がテスト環境でリアルタイムに
反映されブラウザで確認できる点も気に入っています。&lt;&#x2F;p&gt;
&lt;p&gt;まだ記事の移行も終わっていませんし、元のテンプレートからそのまま未修正のもの
もありますが、ぼちぼちと修正していこうと思います。&lt;&#x2F;p&gt;
&lt;p&gt;Deploy先は、AWSの&lt;strong&gt;Amazon Amplify&lt;&#x2F;strong&gt;としました。ゆくゆくメールフォームなども作っ
ていきたいと思います。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;カスタムコンポーネントの活用&quot;&gt;カスタムコンポーネントの活用&lt;&#x2F;h2&gt;
&lt;p&gt;Next.jsとTailwind UIの大きな魅力の1つは、カスタムコンポーネントを簡単に作成
して再利用できる点です。従来のCMSであればプラグインやテンプレートの変更とな
り気軽にできませんが、今のスタイルであればTypescriptでコードを書けばすぐに利
用できます。コードなのでClaude CodeなどのAI支援も活用できます。&lt;&#x2F;p&gt;
&lt;p&gt;例えば、ブログ記事の中でレストランやショップの情報を
綺麗に表示するためのコンポーネントを作成しました。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;tsx&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;&#x2F;&#x2F; src&#x2F;components&#x2F;ShopInfo.tsx&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;interface&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; ShopInfoProps&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable z-object z-property&quot;&gt;  name&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-primitive&quot;&gt; string&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable z-object z-property&quot;&gt;  address&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-primitive&quot;&gt; string&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable z-object z-property&quot;&gt;  osmAddress&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-primitive&quot;&gt; string&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable z-object z-property&quot;&gt;  phone&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-primitive&quot;&gt; string&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable z-object z-property&quot;&gt;  closedDays&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-primitive&quot;&gt; string&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable z-object z-property&quot;&gt;  website&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;?:&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-primitive&quot;&gt; string&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-storage z-type&quot;&gt;export function&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; ShopInfo&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;({&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt;  name&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt;  address&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt;  osmAddress&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt;  phone&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt;  closedDays&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt;  website&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; ShopInfoProps&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;  &#x2F;&#x2F; コンポーネントの実装...&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;このコンポーネントを使用すると、以下のように店舗情報を簡単に表示できます。&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;項目&lt;&#x2F;th&gt;&lt;th&gt;内容&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;店名&lt;&#x2F;td&gt;&lt;td&gt;スターバックスコーヒー 学園都市キャンパススクェア店&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;住所&lt;&#x2F;td&gt;&lt;td&gt;兵庫県 神戸市西区 学園西町1-4 キャンパススクェア&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;地図&lt;&#x2F;td&gt;&lt;td&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.openstreetmap.org&#x2F;?mlat=34.683006&amp;amp;mlon=135.057619#map=17&#x2F;34.683006&#x2F;135.057619&quot;&gt;OpenStreetMap&lt;&#x2F;a&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;電話&lt;&#x2F;td&gt;&lt;td&gt;078-798-7613&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;定休日&lt;&#x2F;td&gt;&lt;td&gt;不定休&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;ウェブサイト&lt;&#x2F;td&gt;&lt;td&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;store.starbucks.co.jp&#x2F;detail-1718&#x2F;&quot;&gt;https:&#x2F;&#x2F;store.starbucks.co.jp&#x2F;detail-1718&#x2F;&lt;&#x2F;a&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;レストランやカフェだけでなく、様々な店舗情報を表示できます。&lt;&#x2F;p&gt;
&lt;p&gt;このようなコンポーネントは、情報を構造化して表示するだけでなく、スタイリングの一貫性を保ち、コードの再利用性を高めるメリットがあります。MDXの中でReactコンポーネントをシームレスに使用できるのは、このブログシステムの大きな魅力の1つです。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;まとめ&quot;&gt;まとめ&lt;&#x2F;h2&gt;
&lt;p&gt;Micro.blogからNext.js × Tailwind Plus × Amazon Apmplify(AWS)へのブログ移行は、
モダンなWeb技術スタックを活用するという点で非常に満足のいく選択でした。&lt;&#x2F;p&gt;
&lt;p&gt;新しいプラットフォームでは、以下のようなメリットを実感しています。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;開発の柔軟性&lt;&#x2F;strong&gt;: フロントエンドとしてReactベースのNext.jsを使うことで、好きなようにカスタマイズできる自由度を得られた&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;執筆体験の向上&lt;&#x2F;strong&gt;: MDXを使うことで、マークダウンの手軽さとReactコンポーネントの柔軟性を両立できる&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;パフォーマンス&lt;&#x2F;strong&gt;: 静的生成とエッジでのレンダリングにより、高速なページ読み込みを実現できた&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;学習機会&lt;&#x2F;strong&gt;: 実際のプロジェクトを通じて最新のWebフロントエンド技術を深く学べる点も大きな魅力&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;もちろん、まだ改善点もあります。コンテンツの移行や検索機能の実装、SEO対策など、今後も少しずつアップデートしていく予定です。自分のペースで改良していける点が、自前のプラットフォームの最大の魅力だと感じています。&lt;&#x2F;p&gt;
&lt;p&gt;Next.jsとTailwind Plusの組み合わせは、Webアプリケーション構築だけでなく
個人ブログの構築においても非常に強力なツールセットになっていると実感しています。
興味がある方はぜひ試してみることをおすすめします。&lt;&#x2F;p&gt;
&lt;section class=&quot;footnotes&quot;&gt;
&lt;ol class=&quot;footnotes-list&quot;&gt;
&lt;li id=&quot;fn-1&quot;&gt;
&lt;p&gt;HMR (Hot Module Replacement)アプリケーション実行中にコードが変更された
時、ページ全体をリロードせずに変更されたモジュールのみを動的に置き換える
技術。Webpackなどのバンドラーがファイル変更を監視し、ウェブソケット接続を通じて変更部分だけをブラウザに送信するため、アプリケーションの状態を保持したまま即座に変更が反映される。 &lt;a href=&quot;#fr-1-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;&#x2F;section&gt;
</content>
        <summary type="html">Micro.blogを利用したブログを運用していましたが、Next.js + Tailwind Plus(旧Tailwind UI)を使ってエンジニアから見て柔軟なブログを再構築してみました。</summary>
        </entry><entry xml:lang="en">
        <title>Exploring Claude Code: Hands-On with Anthropic&#x27;s AI-Powered Coding Assistant</title>
        <published>2025-03-12T00:00:00+00:00</published>
        <updated>2025-03-12T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2025/03/claude-code/" type="text/html"/>
        <id>https://codedchords.dev/blog/2025/03/claude-code/</id>
        
            <content type="html">&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;docs.anthropic.com&#x2F;en&#x2F;docs&#x2F;agents-and-tools&#x2F;claude-code&#x2F;overview&quot;&gt;Claude Code&lt;&#x2F;a&gt;を試してみました。&lt;&#x2F;p&gt;
&lt;p&gt;Claude Codeは、Anthropicが開発した最新のAI駆動型コーディングアシスタントです。
コマンドラインコーディングツールで、AnthropicのサーバーにAPIを介して接続し
Claude 3.7 Sonnetモデルを活用して開発者を支援します。従って、
ブラウザからClaude 3.7 Sonnetを扱うのと同等の高度なAI推論の支援を受けることができます。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;Getting_Started_With_Claude_Code&quot;&gt;Getting Started With Claude Code&lt;&#x2F;h2&gt;
&lt;p&gt;Claude Codeを使う前提がいくつかあります。&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Claude Codeはまだβ版でResearch Previewのため、
&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;docs.anthropic.com&#x2F;en&#x2F;docs&#x2F;agents-and-tools&#x2F;claude-code&#x2F;overview&quot;&gt;Claude Codeのページ&lt;&#x2F;a&gt;からβ版参加のWaiting Listの登録して、アクセ
ス許可をもらう必要があ。&lt;&#x2F;li&gt;
&lt;li&gt;Node.js 18以上が必要。以下のソフトウェアはオプション。&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;ul&gt;
&lt;li&gt;git 2.23+&lt;&#x2F;li&gt;
&lt;li&gt;GitHub or GitLab CLI for PR workflows&lt;&#x2F;li&gt;
&lt;li&gt;ripgrep&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.anthropic.com&#x2F;supported-countries&quot;&gt;Supported Countries&lt;&#x2F;a&gt;に居
る必要。日本は対象となっているので大丈夫。&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;もちろん、ターミナルから使うものなので、MacであればiTerm2などがあったほうが
よいでしょう。&lt;&#x2F;p&gt;
&lt;p&gt;上記がクリアできたら、Claude Codeを認証して使用するために、AnthropicからAPI
キーを生成して払い出しておきます。&lt;&#x2F;p&gt;
&lt;p&gt;Claude Codeのインストールは以下のコマンドで行います。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;npm&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; install -g @anthropic&#x2F;claude-code&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;インストールが完了したら、次のコマンドでClaude Codeを起動して、初回だけOAuth
認証を完了させておきます。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;claude&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;What_Claude_Code_Can_Do_For_You?&quot;&gt;What Claude Code Can Do For You?&lt;&#x2F;h2&gt;
&lt;p&gt;見てもらったほうが早いので、下に操作した例を貼り付けておきます。
適当に作った&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;yostos&#x2F;yostos-portfolio&quot;&gt;Webサイトのリポジトリ
&lt;&#x2F;a&gt;について、分析したのに
&lt;code&gt;README.md&lt;&#x2F;code&gt;の更新を依頼してみました。引用ブロック担っている部分が私の指示したものです。&lt;&#x2F;p&gt;
&lt;p&gt;単純なWebサイトですが、Next.jsを使いそこそこコードの量もありましたが、
数秒で私が適当に書いていた&lt;code&gt;README.md&lt;&#x2F;code&gt;を依存ソフトウェアなども正確に記載し完璧に仕上
げてくれました。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;markdown&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;╭──────────────────────────────────────────────────────────────╮&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;│ ✻ Welcome to Claude Code research preview! │&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;│ │&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;│ &#x2F;help for help │&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;│ │&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;│ cwd: &#x2F;Users&#x2F;yostos&#x2F;ghq&#x2F;github.com&#x2F;yostos&#x2F;yostos-portfolio │&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;╰──────────────────────────────────────────────────────────────╯&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;Tips for getting started:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-list z-begin z-markdown&quot;&gt;1.&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt;  Run &#x2F;init to create a CLAUDE.md file with instructions for Claude.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-list z-begin z-markdown&quot;&gt;2.&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt;  Ask Claude questions about your codebase.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-list z-begin z-markdown&quot;&gt;3.&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt;  Ask Claude to implement changes to your codebase.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-quote z-begin z-markup z-quote&quot;&gt;&amp;gt; プロジェクトの概要を教えてください。これはどのようなプロジェクトで何を目的としていますか？&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;⏺ プロジェクトの概要を調査します。&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;⏺ Task(Please analyze this project to understand its purpose and overview. Check the following:…)…&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;⎿  Done (6 tool uses · 14.6k tokens · 22.1s)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;⏺ これは Next.js で構築された個人ポートフォリオサイトです。ウェブ技術とデザイン手法をテストするための練習プロジェ&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;クトとして開発されています。主な特徴:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-list z-begin z-markdown&quot;&gt;-&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt; Next.js と TypeScript を使用&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-list z-begin z-markdown&quot;&gt;-&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt; Tailwind CSS とdaisyUI でスタイリング&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-list z-begin z-markdown&quot;&gt;-&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt; Three.js と React Three Fiber による3D要素&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-list z-begin z-markdown&quot;&gt;-&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt; Framer Motion によるアニメーション&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-list z-begin z-markdown&quot;&gt;-&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt; AWS サービス（SES、Amplify）をバックエンド機能に使用&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;サイト構成:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-list z-begin z-markdown&quot;&gt;-&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt; 3D要素、サービス、ニュース、作品を含むホームページ&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-list z-begin z-markdown&quot;&gt;-&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt; About ページ&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-list z-begin z-markdown&quot;&gt;-&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt; 問い合わせフォーム&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-list z-begin z-markdown&quot;&gt;-&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt; 作品ポートフォリオ&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-list z-begin z-markdown&quot;&gt;-&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt; 音楽セクション&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-list z-begin z-markdown&quot;&gt;-&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt; ニュース&#x2F;ブログセクション&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-quote z-begin z-markup z-quote&quot;&gt;&amp;gt; では、README.mdは内容を正しく書き示しているでしょうか？もし齟齬があればアップデートしてください。&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;⏺ README.mdの内容を確認します。&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;⏺ Read(file_path: &amp;quot;README.md&amp;quot;)…&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;  ⎿  # Porfolio Site with Next.js&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;個人でWeb技術とデザイン手法の検証を目的として 片手間で作った練習用ポートフォリオです。&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;... (+27 lines)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;⏺ Task(Compare the actual project features and technologies with what&amp;#39;s listed in the README.md. The README seems minimal …&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;and might be missing some technologies used in the project. …)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;⎿  Done (6 tool uses · 18k tokens · 30.4s)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;⏺ READMEには更新が必要です。現在のREADMEは非常にシンプルで、プロジェクトで使われている多くの技術が記載されていませ&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;ん。以下の点を修正すべきです：&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-list z-begin z-markdown&quot;&gt;1.&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt; タイトルのタイプミス（&amp;quot;Porfolio&amp;quot; → &amp;quot;Portfolio&amp;quot;）&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-list z-begin z-markdown&quot;&gt;2.&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt; 使用技術の詳細リスト（Three.js、Framer Motion、AWS services等が未記載）&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-list z-begin z-markdown&quot;&gt;3.&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt; プロジェクト機能の説明（3D要素、ポートフォリオ表示、問い合わせフォーム等）&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;更新しますか？&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-quote z-begin z-markup z-quote&quot;&gt;&amp;gt; 更新してください。また、表記は日本語でお願いします。英語の部分があれば更新してください。&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;⏺ READMEを日本語で更新します。&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;⏺ Update(file_path: README.md)…&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;⎿ Updated README.md with 54 additions and 14 removals&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;1 # Porfolio Site with Next.js&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;1 # ポートフォリオサイト with Next.js&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;2&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;3 個人でWeb技術とデザイン手法の検証を目的として 片手間で作った練習用ポートフォリオです。&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;3 個人でWeb技術とデザイン手法の検証を目的として片手間で作った練習用ポートフォリオです。&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;4&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;5 以下を使用しています。&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;5 ## 使用技術&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;6&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;7 - &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-link z-title z-string z-other z-link z-title z-markdown&quot;&gt;[Next.js]&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-markup z-underline z-link&quot;&gt;https:&#x2F;&#x2F;nextjs.org&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;8 - &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-link z-title z-string z-other z-link z-title z-markdown&quot;&gt;[Tailwind CSS]&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-markup z-underline z-link&quot;&gt;https:&#x2F;&#x2F;tailwindcss.com&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;9 - &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-link z-title z-string z-other z-link z-title z-markdown&quot;&gt;[daisyUI]&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-markup z-underline z-link&quot;&gt;https:&#x2F;&#x2F;daisyui.com&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;7 本プロジェクトでは以下の技術を使用しています。&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;8&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;9 ## Getting Started&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;9 ### フロントエンド&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;10 - &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-link z-title z-string z-other z-link z-title z-markdown&quot;&gt;[Next.js]&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-markup z-underline z-link&quot;&gt;https:&#x2F;&#x2F;nextjs.org&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt; - Reactフレームワーク（サーバーサイドレンダリングとルーティング）&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;11 - &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-link z-title z-string z-other z-link z-title z-markdown&quot;&gt;[React]&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-markup z-underline z-link&quot;&gt;https:&#x2F;&#x2F;reactjs.org&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt; - ユーザーインターフェース構築のためのJavaScriptライブラリ&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;12 - &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-link z-title z-string z-other z-link z-title z-markdown&quot;&gt;[TypeScript]&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-markup z-underline z-link&quot;&gt;https:&#x2F;&#x2F;www.typescriptlang.org&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt; - 型付けされたプログラミング言語&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;13 - &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-link z-title z-string z-other z-link z-title z-markdown&quot;&gt;[Tailwind CSS]&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-markup z-underline z-link&quot;&gt;https:&#x2F;&#x2F;tailwindcss.com&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt; - ユーティリティファーストのCSSフレームワーク&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;14 - &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-link z-title z-string z-other z-link z-title z-markdown&quot;&gt;[daisyUI]&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-markup z-underline z-link&quot;&gt;https:&#x2F;&#x2F;daisyui.com&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt; - Tailwind CSS用コンポーネントライブラリ&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;15 - &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-link z-title z-string z-other z-link z-title z-markdown&quot;&gt;[Three.js]&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-markup z-underline z-link&quot;&gt;https:&#x2F;&#x2F;threejs.org&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt; - WebGL用3Dグラフィックスライブラリ&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;16 - &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-link z-title z-string z-other z-link z-title z-markdown&quot;&gt;[React Three Fiber]&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-markup z-underline z-link&quot;&gt;https:&#x2F;&#x2F;github.com&#x2F;pmndrs&#x2F;react-three-fiber&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt; - Three.js用Reactレンダラー&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;17 - &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-link z-title z-string z-other z-link z-title z-markdown&quot;&gt;[React Three Drei]&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-markup z-underline z-link&quot;&gt;https:&#x2F;&#x2F;github.com&#x2F;pmndrs&#x2F;drei&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt; - React Three Fiber用ヘルパー&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;18 - &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-link z-title z-string z-other z-link z-title z-markdown&quot;&gt;[Framer Motion]&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-markup z-underline z-link&quot;&gt;https:&#x2F;&#x2F;www.framer.com&#x2F;motion&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt; - React用アニメーションライブラリ&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;19&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;20 First, run the development server:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;20 ### バックエンド&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;21 - &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-link z-title z-string z-other z-link z-title z-markdown&quot;&gt;[AWS SES]&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-markup z-underline z-link&quot;&gt;https:&#x2F;&#x2F;aws.amazon.com&#x2F;ses&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt; - 問い合わせフォーム用メールサービス&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;22 - &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-link z-title z-string z-other z-link z-title z-markdown&quot;&gt;[AWS Amplify]&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-markup z-underline z-link&quot;&gt;https:&#x2F;&#x2F;aws.amazon.com&#x2F;amplify&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt; -&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;Webおよびモバイルアプリケーションのためのプラットフォーム&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;23&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;24 ### UI&#x2F;UX&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;25 - &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-link z-title z-string z-other z-link z-title z-markdown&quot;&gt;[FontAwesome]&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-markup z-underline z-link&quot;&gt;https:&#x2F;&#x2F;fontawesome.com&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt; - アイコンライブラリ&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;26 - &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-link z-title z-string z-other z-link z-title z-markdown&quot;&gt;[M PLUS 1 Code]&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-markup z-underline z-link&quot;&gt;https:&#x2F;&#x2F;fonts.google.com&#x2F;specimen&#x2F;M+PLUS+1+Code&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt; - コード表示用の現代的なフォント&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;27&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;28 ## 機能&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;29&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;30 - &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;**&lt;&#x2F;span&gt;&lt;span class=&quot;z-markup z-bold&quot;&gt;3Dインタラクティブ要素&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;**&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt; - Three.jsとReact Three Fiberを用いたインタラクティブな3Dキューブ&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;31 - &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;**&lt;&#x2F;span&gt;&lt;span class=&quot;z-markup z-bold&quot;&gt;レスポンシブデザイン&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;**&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt; - 様々な画面サイズに適応するモバイルフレンドリーなインターフェース&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;32 - &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;**&lt;&#x2F;span&gt;&lt;span class=&quot;z-markup z-bold&quot;&gt;ポートフォリオショーケース&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;**&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt; - 作品サンプルとプロジェクトのギャラリー&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;33 - &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;**&lt;&#x2F;span&gt;&lt;span class=&quot;z-markup z-bold&quot;&gt;問い合わせフォーム&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;**&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt; - AWS SESを統合した直接コミュニケーション用フォーム&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;34 - &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;**&lt;&#x2F;span&gt;&lt;span class=&quot;z-markup z-bold&quot;&gt;ダーク&#x2F;ライトモード&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;**&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt; - テーマ切り替え機能&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;35 - &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;**&lt;&#x2F;span&gt;&lt;span class=&quot;z-markup z-bold&quot;&gt;音楽プレーヤー&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;**&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt; - 音楽ショーケース用SoundCloud統合&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;36&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;37 ## 始め方&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;38&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;39 まず、開発サーバーを実行します:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;40&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;41 `bash&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;     42  npm run dev&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;     43  # or&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;     43  # または&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;     44  yarn dev&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;     45  # or&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;     45  # または&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;     46  pnpm dev&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;     47  # or&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;     47  # または&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;     48  bun dev&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;     49  `&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;50&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;51 Open &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-link z-title z-string z-other z-link z-title z-markdown&quot;&gt;[http:&#x2F;&#x2F;localhost:3000]&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-markup z-underline z-link&quot;&gt;http:&#x2F;&#x2F;localhost:3000&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt; with your browser to see the result.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;51 ブラウザで &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-link z-title z-string z-other z-link z-title z-markdown&quot;&gt;[http:&#x2F;&#x2F;localhost:3000]&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-markup z-underline z-link&quot;&gt;http:&#x2F;&#x2F;localhost:3000&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt; を開くと結果が表示されます。&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;52&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;53 You can start editing the page by modifying &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-raw z-markdown z-markup z-inline z-raw z-string z-markdown&quot;&gt;`app&#x2F;page.tsx`&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt;. The page auto-updates as you edit the file.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;53 &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-raw z-markdown z-markup z-inline z-raw z-string z-markdown&quot;&gt;`app&#x2F;page.tsx`&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;を編集することでページの編集を開始できます。ファイルを編集すると、ページは自動更新されます。&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;54&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;55 This project uses &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-link z-title&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-raw z-markdown z-markup z-inline z-raw z-string z-markdown&quot;&gt;`next&#x2F;font`&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-link z-title&quot;&gt;]&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-markup z-underline z-link&quot;&gt;https:&#x2F;&#x2F;nextjs.org&#x2F;docs&#x2F;app&#x2F;building-your-application&#x2F;optimizing&#x2F;fonts&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;to automatically optimize and load &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-link z-title z-string z-other z-link z-title z-markdown&quot;&gt;[Geist]&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-markup z-underline z-link&quot;&gt;https:&#x2F;&#x2F;vercel.com&#x2F;font&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt;, a new font family for Vercel.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;55 ## 環境変数&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;56&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;57 問い合わせフォーム機能を使用するには、以下のAWS環境変数を設定する必要があります:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;58&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;59 `      60  AWS_ACCESS_KEY_ID=あなたのAWSアクセスキー&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;     61  AWS_SECRET_ACCESS_KEY=あなたのAWSシークレットキー&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;     62  SES_REGION=あなたのAWSリージョン (デフォルト: ap-northeast-1)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;     63  SES_FROM_EMAIL=送信者メールアドレス&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;     64  SES_TO_EMAIL=受信者メールアドレス&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;     65  `&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;66&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;67 ## その他&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;68&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;69 このプロジェクトでは&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-link z-title&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-raw z-markdown z-markup z-inline z-raw z-string z-markdown&quot;&gt;`next&#x2F;font`&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-link z-title&quot;&gt;]&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-markup z-underline z-link&quot;&gt;https:&#x2F;&#x2F;nextjs.org&#x2F;docs&#x2F;app&#x2F;building-your-application&#x2F;optimizing&#x2F;fonts&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt; を使用して、&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;最適なパフォーマンスのためにカスタムフォントを自動的に最適化して読み込んでいます。&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;⏺ README.mdを日本語に完全更新しました。以下の内容を追加・修正しました：&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-list z-begin z-markdown&quot;&gt;1.&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt; タイトルを「ポートフォリオサイト with Next.js」に修正&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-list z-begin z-markdown&quot;&gt;2.&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt; 詳細な技術スタックをフロントエンド、バックエンド、UI&#x2F;UXの3セクションに分けて記載&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-list z-begin z-markdown&quot;&gt;3.&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt; プロジェクトの主要機能（3D要素、レスポンシブデザイン、ポートフォリオ機能など）を追加&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-list z-begin z-markdown&quot;&gt;4.&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt; 環境変数の設定方法も追加&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-list z-begin z-markdown&quot;&gt;5.&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt; すべての英語部分を日本語に翻訳&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;これでREADMEは実際のプロジェクトの機能と技術をより正確に反映しています。&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;│ &amp;gt; quit │&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;! for bash mode · &#x2F; for commands · esc to undo ✓ Update installed · Restart to apply&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;まとめ&quot;&gt;まとめ&lt;&#x2F;h2&gt;
&lt;p&gt;今回はAnthropicが開発したAI駆動型コーディングアシスタント「Claude Code」を試
してみました。まだResearch Previewの段階ですが、その能力は非常に印象的です。
コマンドラインから簡単に使用でき、コードベースの分析や更新を数秒で行うことが
できます。&lt;&#x2F;p&gt;
&lt;p&gt;実際の使用例として示したように、プロジェクトの概要を理解し、READMEの更新を行
う作業も正確かつ迅速に実行してくれました。Claude 3.7 Sonnetモデルの高度な推
論能力をコマンドラインから活用できることで、開発ワークフローが大幅に効率化さ
れる可能性を感じました。&lt;&#x2F;p&gt;
&lt;p&gt;AI駆動型の開発支援ツールはますます進化しており、Claude Codeはその最前線にあ
るツールの1つと言えるでしょう。今後の正式リリースや機能拡張に期待したいと思
います。&lt;&#x2F;p&gt;
</content>
        <summary type="html">I tried Claude Code.Claude Code is the latest AI-driven coding assistant developed by Anthropic.It&#x27;s a command-line coding tool that connects to Anthropic&#x27;s servers via API andutilizes the Claude 3.7 Sonnet model to support developers. Therefore,you can receive the same level of advanced AI reasoning support as when using Claude 3.7 Sonnet from a browser.</summary>
        </entry><entry xml:lang="en">
        <title>ウェブデザイン技能検定は必要か？ - 技術変化の時代の資格価値</title>
        <published>2025-03-09T00:00:00+00:00</published>
        <updated>2025-03-09T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2025/03/web-design/" type="text/html"/>
        <id>https://codedchords.dev/blog/2025/03/web-design/</id>
        
            <content type="html">&lt;p&gt;少しだけ通ったVY訓練校では、&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.sikaku.gr.jp&#x2F;web&#x2F;wc&#x2F;&quot;&gt;Webクリエイター能力認定試験&lt;&#x2F;a&gt;が取得できそうことを言っていました。内容見ると、メモ帳でHTMLを書かすようなアホな試験でした。
何かで有利に働くこともなさそうです。受験者数は多そうですが、一体何を目指しているんでしょうか。&lt;&#x2F;p&gt;
&lt;p&gt;気になってWEBデザイン関連の認定資格を調べていたら、「&lt;strong&gt;ウェブデザイン技能検定&lt;&#x2F;strong&gt;」という国家検定があるのに気付きました。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;資格試験の現状と基本構造&quot;&gt;資格試験の現状と基本構造&lt;&#x2F;h2&gt;
&lt;p&gt;ウェブデザイン技能検定は、厚生労働省が認定する国家検定制度として2008年に創設されています。
運営は厚生労働大臣指定試験機関である特定非営利活動法人&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.netskill.jp&#x2F;&quot;&gt;インターネットスキル認定普及協会&lt;&#x2F;a&gt;が行っています。
この検定は職業能力開発促進法に基づく技能検定の1つであり、Webデザインにおけ
る実務的な技能を公的に証明するものです。1級から3級までのレベル別に実施さ
れています。&lt;&#x2F;p&gt;
&lt;p&gt;ウェブデザイン技能検定1級では、HTML5、CSS3、JavaScript等のコーディング技術に加え、情報設計、ユーザビリティ、アクセシビリティなどの幅広い知識が問われます。Webサイト全体の設計や企画、ディレクション能力も評価対象です。出題形式は選択問題、記述問題、実技課題があります。&lt;&#x2F;p&gt;
&lt;p&gt;特定非営利活動法人インターネットスキル認定普及協会が公開している&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.webdesign.gr.jp&#x2F;pass&#x2F;&quot;&gt;取得者数&lt;&#x2F;a&gt;を確認すると、過去五年間の受験者数と合格者数は次のとおりです。&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;年度&lt;&#x2F;th&gt;&lt;th&gt;受験者数&lt;&#x2F;th&gt;&lt;th&gt;合格者数&lt;&#x2F;th&gt;&lt;th&gt;合格率&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;2019年度&lt;&#x2F;td&gt;&lt;td&gt;51人&lt;&#x2F;td&gt;&lt;td&gt;12人&lt;&#x2F;td&gt;&lt;td&gt;23.5%&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;2020年度&lt;&#x2F;td&gt;&lt;td&gt;46人&lt;&#x2F;td&gt;&lt;td&gt;8人&lt;&#x2F;td&gt;&lt;td&gt;17.4%&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;2021年度&lt;&#x2F;td&gt;&lt;td&gt;51人&lt;&#x2F;td&gt;&lt;td&gt;9人&lt;&#x2F;td&gt;&lt;td&gt;17.6%&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;2022年度&lt;&#x2F;td&gt;&lt;td&gt;61人&lt;&#x2F;td&gt;&lt;td&gt;3人&lt;&#x2F;td&gt;&lt;td&gt;4.9%&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;2023年度&lt;&#x2F;td&gt;&lt;td&gt;63人&lt;&#x2F;td&gt;&lt;td&gt;9人&lt;&#x2F;td&gt;&lt;td&gt;14.3%&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;1級になるとなかなかの難関です。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;技術的乖離_-_古い技術標準&quot;&gt;技術的乖離 - 古い技術標準&lt;&#x2F;h2&gt;
&lt;p&gt;技能検定の内容や対策本などから検定で求められている技術やスキルを確認してみました。&lt;&#x2F;p&gt;
&lt;p&gt;内容を見る限り、最新の技術スタックに追いついておらず、一昔前の技術標準にとどまっているようです。&lt;&#x2F;p&gt;
&lt;p&gt;例えばJavaScriptについては、ES6(ECMAScript 2015)以降の最新機能への対応が限定的であり、
主にES5レベルの機能に基づいていると推測されます。
出題傾向を見る限り、アロー関数、Promise、async&#x2F;await、モジュールシステムなど、現代のJavaScript開発において標準となっている多くの機能が試験範囲外となっているのかなと思います。
公式資料では明確なバージョン指定はありませんが、基本的なDOM操作やコールバックパターンが中心となっており、2015年以降に標準化された現代的な実装手法との間に大きなギャップが生じています。&lt;&#x2F;p&gt;
&lt;p&gt;現在のウェブ開発現場ではReact、Vue、Angularなどのフレームワークが標準的に使用されていますが、技能検定ではこれらモダンフレームワークについては全く扱っていないようです。また、現代のウェブ開発においてnpm、Webpack、Vite等のビルドツール、Gitなどのバージョン管理システム、CIパイプラインなどは標準的な環境では必須ですが、技能検定にはほとんど言及がなく、従来型の静的なファイル編集アプローチに留まっている可能性があります。&lt;&#x2F;p&gt;
&lt;p&gt;WEBデザイナーがフロントエンドエンジニアと呼ばれる現状において、モダンフレームワークやモダンなツールチェーンを知らず従来型のJavaScriptとjQueryの知識のみでは就職市場での競争力の足しになりそうな気がしません。コンポーネント指向開発の概念や状態管理といった現代的なアプローチが試験に含まれていないことも、実務との乖離を深めているように思います。
モダンな開発ワークフローへの理解がないまま現場に出てしまっては、実務での大きな壁となりそうです。&lt;&#x2F;p&gt;
&lt;p&gt;イメージ的は2000年代によく見かけたHTML&#x2F;CSS&#x2F;Javascriptが書けてPHP(今どき
PHP)もちょっと書ける「Webデザイナー」でしょうか。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;グローバル標準との比較&quot;&gt;グローバル標準との比較&lt;&#x2F;h2&gt;
&lt;p&gt;他の国の同じような認定制度と比較してみました。&lt;&#x2F;p&gt;
&lt;p&gt;米国では、ウェブデザイン技能検定と似たような認定制度は以下のようなものでしょう。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;W3Schools Certified Web Developer&#x2F;Designer&lt;&#x2F;strong&gt; - HTML, CSS, JavaScriptなど基本的なウェブ技術の知識を証明する国際的なオンライン認定&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;freeCodeCamp Certifications&lt;&#x2F;strong&gt; - 無料だが業界で認知度が高まっているウェブ開発認定プログラム&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;CIW (Certified Internet Web Professional)&lt;&#x2F;strong&gt; - ウェブデザインおよび開発に関する体系的な国際認定制度&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;W3SchoolsとCIWは比較的伝統的なウェブ技術に焦点を当てており、ウェブデザイ
ン技能検定と近いかもしれません。freeCodeCampは現代的な技術スタックをカバー
しているようです。&lt;&#x2F;p&gt;
&lt;p&gt;いずれも米国市場ではデザイナーのキャリアとしては、ほとんど評価されず意味がありません。
これらの認定に時間をかけるならAWSやGoogleなどの認定資格のほうが市場価値はあり、
給与へ直接インパクトがあります。&lt;&#x2F;p&gt;
&lt;p&gt;海外の採用市場では、特定のフレームワーク（React、Angular、Vue.js）
の実践的経験や、AWS&#x2F;Google Cloud等のクラウドサービスの知識が重視されます。
国際的な企業の採用基準では、現場で使われているツールや技術への適応能力が最優先される傾
向にあります。
実務から乖離した資格よりも、実務で実践したポートフォリオや有力なプラットフォームの知識が評価されます。&lt;&#x2F;p&gt;
&lt;p&gt;特にAWS&#x2F;Google&#x2F;Azureの認定などは技術の変化に伴い、認定内容自体も常に更新されており、認定も2年程度の有効期間があり、再認定が必要なため、継続的に最新の技術にキャッチアップし学習が必要です。だからこそ、評価されているのでしょう。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;まとめ&quot;&gt;まとめ&lt;&#x2F;h2&gt;
&lt;p&gt;ウェブデザイン技能検定は学科と実技合わせると32,000円もの費用が検定に必要です。&lt;&#x2F;p&gt;
&lt;p&gt;検定の難度と、業界で求められるスキルの証明にならなさそうなことを考えると、
取得する価値はあまりなさそうです。&lt;&#x2F;p&gt;
</content>
        <summary type="html">最近気になってWEBデザイン関連の認定資格を調べていたら、「ウェブデザイン技能検定」という国家検定があるのに気付きました。折角なので、深掘りして調べてみました。</summary>
        </entry><entry xml:lang="en">
        <title>エンジニアのためのポートフォリオサイトの構築</title>
        <published>2025-03-08T00:00:00+00:00</published>
        <updated>2025-03-08T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2025/03/portfolio-site-for-engieer/" type="text/html"/>
        <id>https://codedchords.dev/blog/2025/03/portfolio-site-for-engieer/</id>
        
            <content type="html">&lt;p&gt;今更ながら年初からWebデザインを教わるというシーンがありました。
しかし、毎朝タイピング練習で始まり、
「BRタグは非奨励」などとW3Cの仕様を知らないレベルの講師が
レベルの低い授業をやっていました。
100年かけてもWebデザインに行きつきそうにない。吐き気がしました。
割り切って我慢できるレベルを超えていました。&lt;&#x2F;p&gt;
&lt;p&gt;辞めましたが、
まぁ折角なのでWEBデザイナーが作るらしい「ポートフォリオ」なるものを、
3日ほど使ってこれまで深くやってこなかった技術スタックを作ってみました。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;はじめに&quot;&gt;はじめに&lt;&#x2F;h2&gt;
&lt;p&gt;ポートフォリオサイトは自分のスキルや実績を効果的にアピールするための重要な
ツールらしいです。&lt;&#x2F;p&gt;
&lt;p&gt;Illustratorでデザインカンプ描いて、HTML&#x2F;CSSでせっせとコーディング
なんてサイト作っても一体誰が見るんでしょう。
「あぁ、いいデザインだね」とか褒められると
本気で思っているバカがいるのでしょうか？
美的デザインだけで勝負するなんて、よほどの審美眼とセンスがないと無駄です。&lt;&#x2F;p&gt;
&lt;p&gt;この記事では、そんな90年代風なWebサイトでなく、
Node.js上でモダンなWebフレームワークであるNext.js&#x2F;ReactとCSSフレームワークのTailwindCSS、
そしてUIコンポーネントを提供するdaisyUIを組み合わせて
ポートフォリオサイトを構築したのでそれを記録しています。&lt;&#x2F;p&gt;
&lt;p&gt;そして、結局このブログサイトも同じような技術スタック使って
再構築してしまいました。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;使用する技術スタック&quot;&gt;使用する技術スタック&lt;&#x2F;h2&gt;
&lt;p&gt;言語は型安全なTypeScriptを使用し、node&#x2F;Reactベースで以下のようなフレームワークを使っています。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Next.js&lt;&#x2F;strong&gt;: Reactベースのフルスタックフレームワーク&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;TailwindCSS&lt;&#x2F;strong&gt;: ユーティリティファーストのCSSフレームワーク&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;daisyUI&lt;&#x2F;strong&gt;: TailwindCSSのプラグインであるUIコンポーネントライブラリ&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;React Three Fiber&lt;&#x2F;strong&gt;: 3DグラフィックスをReactで簡単に使うためのライブラリ&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Font Awesome&lt;&#x2F;strong&gt;: グラフィカルなアイコン文字を使うためのライブラリ&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Framer Motion&lt;&#x2F;strong&gt;: Framer Motionは、Reactアプリケーションにアニメーションを実装するためのライブラリ&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;AWS SDK&lt;&#x2F;strong&gt;: 問い合わせフォームからAWSのAmanzon SESを使ってメールを送信するため&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;プロジェクトセットアップ&quot;&gt;プロジェクトセットアップ&lt;&#x2F;h2&gt;
&lt;ol&gt;
&lt;li&gt;プロジェクトを作成&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# Next.jsプロジェクトの作成（TypeScript対応）&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;npx&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; create-next-app@latest my-portfolio --typescript&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;√&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; Would you like to use ESLint? ... Yes&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;√&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; Would you like to use Tailwind CSS? ... Yes&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;√&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; Would you like to use&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-evaluation z-backticks z-shell&quot;&gt; `&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;src&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-evaluation z-backticks z-shell&quot;&gt;`&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; directory?&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; ... Yes（好みに応じて）&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;√&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; Would you like to use App Router? ... Yes&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;√&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; Would you like to customize the default import alias&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; (@&#x2F;*)&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;?&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; ... Yes&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;√&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; What import alias would you like configured? ... @&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt;*&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# 作成したプロジェクトディレクトリに移動&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-function z-builtin&quot;&gt;cd&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; my-portfolio&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# daisyUIのインストール&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;npm&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; install daisyui&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;tailwind.config.jsの設定&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;プロジェクトルートにある&lt;code&gt;tailwind.config.js&lt;&#x2F;code&gt;ファイルを開き、daisyUIをプラグインとして追加します。&lt;&#x2F;p&gt;
&lt;p&gt;ライトとダーク両方のテーマをサポートするようにします。設定によりシステムのダーク／ライトモードの設定に応じて切り替わります。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment&quot;&gt;&#x2F;**&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; @&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;type&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; {&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt;import(&amp;#39;tailwindcss&amp;#39;).Config&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment&quot;&gt; *&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-type z-object z-module z-js&quot;&gt;module&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-object z-module z-js&quot;&gt;exports&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;  content&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; [&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;    &amp;quot;.&#x2F;src&#x2F;pages&#x2F;**&#x2F;*.{js,ts,jsx,tsx,mdx}&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;    &amp;quot;.&#x2F;src&#x2F;components&#x2F;**&#x2F;*.{js,ts,jsx,tsx,mdx}&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;    &amp;quot;.&#x2F;src&#x2F;app&#x2F;**&#x2F;*.{js,ts,jsx,tsx,mdx}&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;  ]&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;  theme&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    extend&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;      &#x2F;&#x2F; 必要に応じてテーマの拡張を追加&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    },&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;  },&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;  plugins&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;require&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;daisyui&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;)]&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;  daisyui&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    themes&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;light&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;dark&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;]&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt; &#x2F;&#x2F; 使用するテーマを設定&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;  },&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;};&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;他のライブラリをインストール&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;npm&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; install three @react-three&#x2F;fiber @react-three&#x2F;drei&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;npm&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; install framer-motion&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;npm&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; install @fortawesome&#x2F;fontawesome-svg-core&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;            @fortawesome&#x2F;free-solid-svg-icons&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;            @fortawesome&#x2F;free-regular-svg-icons&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;            @fortawesome&#x2F;free-brands-svg-icons&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;            @fortawesome&#x2F;react-fontawesome&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;npm&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; install aws-amplify @aws-sdk&#x2F;client-ses @aws-sdk&#x2F;client-sts&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;ol start=&quot;4&quot;&gt;
&lt;li&gt;turbooackの有効化&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;Next.jsの開発サーバーを高速化するために、package.jsonのscriptsセクションを編集してturbopackを有効にします。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;json&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;scripts&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;: &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;  &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;dev&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;next dev --turbopack&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;  &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;build&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;next build&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;  &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;start&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;next start&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;  &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-property-name z-json&quot;&gt;lint&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;next lint&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;プロジェクトの構造&quot;&gt;プロジェクトの構造&lt;&#x2F;h2&gt;
&lt;p&gt;Next.jsのAppRouterを使用した基本的なプロジェクト構造を整えると、次のようなフォルダ構成になるはずです。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;my-portfolio&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;├── src&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;│   ├── app&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;│   │   ├── about&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;│   │   │   └── page.tsx （自己紹介ページ）&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;│   │   ├── api&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;│   │   │   └── contact&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;│   │   │       └── route.ts （メール送信）&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;│   │   ├── contact&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;│   │   │   └── page.tsx （お問い合わせページ）&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;│   │   ├── globals.css （グローバルスタイル）&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;│   │   ├── layout.tsx （ルートレイアウト）&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;│   │   ├── page.tsx （トップページ）&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;│   │   └── works&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;│   │       └── page.tsx （作品紹介ページ）&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;│   └── components&#x2F; （共通コンポーネント）&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;├── public&#x2F; （静的ファイル）&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;├── next.config.js&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;├── package.json&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;├── tailwind.config.js&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;└── tsconfig.json&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;AWS_Amplify_へのデプロイ&quot;&gt;AWS Amplify へのデプロイ&lt;&#x2F;h2&gt;
&lt;p&gt;今回はNext.jsアプリケーションのホスティング先としてVercelではなく、AWS Amplifyを選択しました。Amplifyを選んだ理由と、デプロイプロセスについて共有します。&lt;&#x2F;p&gt;
&lt;p&gt;Amplifyを選んだ理由は、次の通りです。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;AWSエコシステムとの統合&lt;&#x2F;strong&gt;: Amazon SESなど他のAWSサービスとの連携がシーム
レスで、同じAWSコンソールから管理できる&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;既存のAWS知識の活用&lt;&#x2F;strong&gt;: Amplify自体は今回初見だが一応前職なので管理コンソールなどは慣れており、
Vercelを新たに学ぶ手間が不要だった。&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;料金体系&lt;&#x2F;strong&gt;: 今回の内容であれば無料枠で十分&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;デプロイ手順をざっくり並べると次の通りです。&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;AWS管理コンソールからAmplifyサービスにアクセス&lt;&#x2F;li&gt;
&lt;li&gt;「新しいアプリを作成」→「GitHubからホスティング」を選択&lt;&#x2F;li&gt;
&lt;li&gt;リポジトリと使用するブランチを選択（今回は&lt;code&gt;main&lt;&#x2F;code&gt;ブランチ）&lt;&#x2F;li&gt;
&lt;li&gt;ビルド設定を確認（Next.jsの場合は自動的に検出される）。認証情報などは面
倒なので以下のようにビルドステップに組み込んだ。&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;yaml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;version&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;frontend&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;  phases&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;    preBuild&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;      commands&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;        -&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; npm ci&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;        # 認証情報の書き込み&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;        # クライアント再度で必要な環境変数&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;        -&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; echo &amp;quot;NEXT_PUBLIC_XXXX_API_URL=https:&#x2F;&#x2F;api.example.com&amp;quot; &amp;gt;&amp;gt;.env&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;        # サーバーサイド限定の環境変数&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;        -&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; echo &amp;quot;AWS_XXXXX_ACCESS_KEY_ID=&amp;quot;hogehogetaratara&amp;quot; &amp;gt;&amp;gt; .env&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;    build&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;      commands&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;        -&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; npm run build&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;  artifacts&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;    baseDirectory&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; .next&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;    files&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;      -&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;**&#x2F;*&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;  cache&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-tag z-yaml&quot;&gt;    paths&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-key-value&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;      -&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; node_modules&#x2F;**&#x2F;*&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;コンポーネント、その他について&quot;&gt;コンポーネント、その他について&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;ヘッダー・コンポーネントについてはdaisyUIのNavbarを使わず、レスポンシブ対応、メニューの開閉に対応している。Navbarを使わない理由はないと思われるが、今回は実装検証のため自身で対応してみた。&lt;&#x2F;li&gt;
&lt;li&gt;Works(作品)コンポーネントについては、トップページと作品ページで共用するため、作品情報をコンポーネントに内包させ引数で表示する作品の数を制御している。&lt;&#x2F;li&gt;
&lt;li&gt;一方でニュースのリストを作成するNewsコンポーネントは、現時点ではTopページしか使っていないが他のページでも使いまわせると考え、ニュース自体はコンポーネントに引数で渡すようにしている。&lt;&#x2F;li&gt;
&lt;li&gt;グラフィカルな要素があまりないので3Dの立方体をトップページに置いている。3DCubeコンポーネントはモデリングする手間が面倒で、立方体をくるくる回しているだけである。&lt;&#x2F;li&gt;
&lt;li&gt;問い合わせフォームは、自身で検証したかったのでAmazon SESを使って実際にフォームをメールで飛ばすところまで作り込んでいる。必要な宛先アドレスや認証情報は、ビルド時に設定して環境変数で受け渡している。認証情報はシークレット情報経由などの方が良いと思われるが、どうもうまくいかなかったので妥協した。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;具体的なソースは、&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;yostos&#x2F;yostos-portfolio&quot;&gt;GitHubで公開&lt;&#x2F;a&gt;しています。なお、ポートフォリオサイト自体は運用コスト等の都合で既に公開を終了しました。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;まとめ&quot;&gt;まとめ&lt;&#x2F;h2&gt;
&lt;p&gt;今回初めてまともにNext.jsを使いました。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;今回はインターラクティブな要素もあったのでSEO的には良くないと思われるが、SSR&#x2F;SSGを使わず全てクライアントコンポーネントとした。&lt;&#x2F;li&gt;
&lt;li&gt;ファイルベースのルーティングは直感的で分かりやすいと感じた。&lt;&#x2F;li&gt;
&lt;li&gt;APIルートでバックエンドの開発も同じプロジェクトでできるので、開発を分離することなくスムーズで行うことが出来そうである。フルスタックの開発者である前提ではあるが。&lt;&#x2F;li&gt;
&lt;li&gt;今回はVercelでなく、GitHubと連携させてAWSのAmplifyにデプロイした。思いの外スムーズにデプロイできた。&lt;&#x2F;li&gt;
&lt;li&gt;CMSのようにテンプレートベースでなく、コードベースで部品の再利用、共通化ができるので、プログラマーがサイトを作るには非常にCMS特有のテンプレートのお手前を覚える必要がないので生産性がよい感じである。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;楽しいお遊びでした。&lt;&#x2F;p&gt;
</content>
        <summary type="html">あまり経験してこなかった技術スタックでポートフォリオサイトを作ってみました</summary>
        </entry><entry xml:lang="en">
        <title>How to Configure Tinylytics Analytics for Production Environment Only</title>
        <published>2025-02-25T00:00:00+00:00</published>
        <updated>2025-02-25T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2025/02/houw-to-configure-tinylytics-analytics/" type="text/html"/>
        <id>https://codedchords.dev/blog/2025/02/houw-to-configure-tinylytics-analytics/</id>
        
            <content type="html">&lt;h2 id=&quot;Why_is_this_code_needed?&quot;&gt;Why is this code needed?&lt;&#x2F;h2&gt;
&lt;p&gt;When incorporating tinylytics javascript, accesses during development are also reflected in the statistics, so we added code so that statistics are obtained only in production. There may be a better way to do this, but for now, I&#x27;ll introduce it here because it does what I want to do.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;How_this_code_works&quot;&gt;How this code works&lt;&#x2F;h2&gt;
&lt;p&gt;This code works as follows:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;When the page loads, JavaScript checks the current hostname (domain)&lt;&#x2F;li&gt;
&lt;li&gt;Only if the hostname exactly matches &quot;your.domain.com&quot;, it will add the tinylytics script&lt;&#x2F;li&gt;
&lt;li&gt;For all other domains (such as localhost or staging environments), the script won&#x27;t be added. Only a console message will be displayed&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;h2 id=&quot;Implementation&quot;&gt;Implementation&lt;&#x2F;h2&gt;
&lt;p&gt;Place this code in the &amp;lt;head&amp;gt; section of your HTML and remove the original tinylytics script tag.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;&amp;lt;!--&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt; Check domain and enable analytics only for specific domain&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; --&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;script&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;  &#x2F;&#x2F; Get current hostname&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;  const currentHostname = window.location.hostname;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;  &#x2F;&#x2F; Specify production domain&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;  const productionDomain = &amp;#39;your.domain.com&amp;#39;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;  &#x2F;&#x2F; Only load analytics on production domain&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;  if (currentHostname === productionDomain) &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;    &#x2F;&#x2F; Dynamically add tinylytics script&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt;    const analyticScript&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; document&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;createElement&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;#39;script&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    analyticScript&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-property z-js&quot;&gt;src&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;#39;https:&#x2F;&#x2F;tinylytics.app&#x2F;embed&#x2F;Xx-xxxxxxxxxxxxxx.js&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    analyticScript&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-property z-js&quot;&gt;defer&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language z-boolean&quot;&gt; true&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    document&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;head&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;appendChild&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-variable z-other z-readwrite&quot;&gt;(analyticScript);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    console&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;log&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;#39;Production environment: Analytics enabled&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;  }&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; else &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    console&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;log&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;#39;Development environment: Analytics disabled&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;  }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-tag&quot;&gt;script&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-tag&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;</content>
        <summary type="html">I have tried to prevent tinylytics stats from being retrieved outside of the production environment.</summary>
        </entry><entry xml:lang="en">
        <title>ChromaLensCLI: Command Line Color Accessibility Validation</title>
        <published>2025-01-25T00:00:00+00:00</published>
        <updated>2025-01-25T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2025/01/chromalenscli-command-line-color-accessibility/" type="text/html"/>
        <id>https://codedchords.dev/blog/2025/01/chromalenscli-command-line-color-accessibility/</id>
        
            <content type="html">&lt;p&gt;とりあえず色覚異常の方にも画像が正しく認識できてるか確認するためのツール &lt;code&gt;ChromaLens CLI&lt;&#x2F;code&gt;を作ってみた。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;ChromaLens_CLIの使い方&quot;&gt;ChromaLens CLIの使い方&lt;&#x2F;h2&gt;
&lt;p&gt;使い方は、次の通り。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;.&#x2F;chromalens&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; input.jpg output.jpg --type tritanopia&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;これで色覚異常の方が実際どのようにインプットとなる画像が見えているかシミュ
レーションした画像が出力されます。
&lt;code&gt;type&lt;&#x2F;code&gt; オプションの指定は次の通りです。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;protanopia (1型色覚)&lt;&#x2F;li&gt;
&lt;li&gt;deuteranopia (2型色覚)&lt;&#x2F;li&gt;
&lt;li&gt;tritanopia (3型色覚)&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h4 id=&quot;ChromeLens_CLIの環境設定&quot;&gt;ChromeLens CLIの環境設定&lt;&#x2F;h4&gt;
&lt;p&gt;以下は、venvでPythonの仮想環境を作って必要なパッケージをインストールする手順です。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;python3&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; -m venv venv&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-function z-builtin&quot;&gt;source&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; venv&#x2F;bin&#x2F;activate.fish&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;pip&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; install numpy Pillow&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;以下が実際のコードです。&lt;code&gt;chromalens&lt;&#x2F;code&gt;というファイル名で保管ください。授業中に書いたコードなので、エラー処理などは省いています。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;python&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;#!&#x2F;usr&#x2F;bin&#x2F;env python3&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;from&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; PIL&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; import&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; Image&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;class&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-type&quot;&gt; ColorVisionSimulator&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    MATRICES&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;        &amp;#39;protanopia&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; np&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;array&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;([&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;            [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;0.567&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 0.433&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 0.000&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;],&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;            [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;0.558&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 0.442&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 0.000&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;],&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;            [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;0.000&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 0.242&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 0.758&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;        ]),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;        &amp;#39;deuteranopia&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; np&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;array&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;([&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;            [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;0.625&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 0.375&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 0.000&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;],&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;            [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;0.700&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 0.300&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 0.000&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;],&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;            [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;0.000&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 0.300&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 0.700&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;        ]),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;        &amp;#39;tritanopia&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; np&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;array&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;([&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;            [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;0.950&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 0.050&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 0.000&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;],&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;            [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;0.000&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 0.433&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 0.567&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;],&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;            [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;0.000&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 0.475&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 0.525&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;        ])&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-python&quot;&gt;    def&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; simulate&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-function z-language z-special z-self z-python&quot;&gt;self&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt; image_path&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt; output_path&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt; cvd_type&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;):&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-control z-flow z-python&quot;&gt;        if&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; cvd_type&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-logical z-python&quot;&gt; not in&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-language z-special z-self z-python&quot;&gt; self&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;MATRICES&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-control z-flow z-python&quot;&gt;            raise&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-exception z-python&quot;&gt; ValueError&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-string z-python&quot;&gt;f&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&amp;quot;Unsupported CVD type. Choose from: &lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-format z-placeholder z-other z-python&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;#39;, &amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;join&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-language z-special z-self z-python&quot;&gt;self&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;MATRICES&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;keys&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;())&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-format z-placeholder z-other z-python&quot;&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;        # 画像を読み込み&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;        img&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; Image&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;open&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;image_path&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;        # RGBAの場合はRGBに変換&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-control z-flow z-python&quot;&gt;        if&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; img&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;mode&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; ==&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;#39;RGBA&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;            img&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; img&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;convert&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;#39;RGB&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;        # NumPy配列に変換&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;        img_array&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; np&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;array&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;img&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;        # 色変換行列を適用&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;        matrix&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-language z-special z-self z-python&quot;&gt; self&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;MATRICES&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;cvd_type&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;        shape&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; img_array&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;shape&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;        pixels&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; img_array&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;reshape&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;-&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;1&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 3&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;        converted&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; np&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;dot&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;pixels&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt; matrix&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;T&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;        # 値を0-255の範囲に収める&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;        converted&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; np&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;clip&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;converted&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 0&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 255&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;        converted&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; converted&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;reshape&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;shape&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;        # 画像として保存&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;        result&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; Image&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;fromarray&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;converted&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;astype&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;#39;uint8&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;),&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;#39;RGB&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;        result&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;save&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;output_path&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-python&quot;&gt;def&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; main&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;():&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    parser&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; argparse&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;ArgumentParser&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt;description&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;#39;Color Vision Deficiency Simulator&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    parser&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;add_argument&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;#39;input&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt; help&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;#39;Input image path&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    parser&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;add_argument&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;#39;output&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt; help&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;#39;Output image path&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    parser&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;add_argument&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;#39;--type&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;#39;-t&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt; choices&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;#39;protanopia&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;#39;deuteranopia&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;#39;tritanopia&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;],&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt;                        required&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language z-python&quot;&gt;True&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt; help&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;#39;Type of color vision deficiency&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    args&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; parser&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;parse_args&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    simulator&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt; ColorVisionSimulator&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-control z-flow z-python&quot;&gt;    try&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;        simulator&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;simulate&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;args&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;input&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt; args&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;output&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt; args&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;type&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-function z-builtin z-python&quot;&gt;        print&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-string z-python&quot;&gt;f&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&amp;quot;Simulation complete: &lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-format z-placeholder z-other z-python&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;args&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;output&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-format z-placeholder z-other z-python&quot;&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-control z-flow z-python&quot;&gt;    except&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-exception z-python&quot;&gt; Exception&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-control z-flow z-python&quot;&gt; as&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; e&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-function z-builtin z-python&quot;&gt;        print&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-string z-python&quot;&gt;f&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&amp;quot;Error: &lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-format z-placeholder z-other z-python&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-python&quot;&gt;str&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;e&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-format z-placeholder z-other z-python&quot;&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-function z-builtin z-python&quot;&gt;        exit&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;1&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-control z-flow z-python&quot;&gt;if&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-variable z-magic z-python&quot;&gt; __name__&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; ==&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;#39;__main__&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;    main&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;</content>
        <summary type="html">デザイン入門のようなコースをうけていて「色覚異常の方もいるので気をつけましょうね」とか説明されてんだけど、そんな適当な説明じゃなくちゃんとAccessibilityについて説明しろよと思う。だいたい「気をつける」のでなく、世の中にはちゃんとチェックするツールもあるし・・・・</summary>
        </entry><entry xml:lang="en">
        <title>How to Merge and Optimize Your PDF Files</title>
        <published>2025-01-10T00:00:00+00:00</published>
        <updated>2025-01-10T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2025/01/how-to-merge-and-optimize-pdf/" type="text/html"/>
        <id>https://codedchords.dev/blog/2025/01/how-to-merge-and-optimize-pdf/</id>
        
            <content type="html">&lt;h2 id=&quot;Bypassing_PDF_Password_Protection&quot;&gt;Bypassing PDF Password Protection&lt;&#x2F;h2&gt;
&lt;p&gt;While the DJI Neo user manual is provided in PDF format, it&#x27;s password-protected, preventing any modifications or merging. Here&#x27;s how to bypass the password protection on a Mac:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Open the PDF in the Preview app&lt;&#x2F;li&gt;
&lt;li&gt;Select &quot;Print&quot; from the File menu (note: not &quot;Export&quot;)&lt;&#x2F;li&gt;
&lt;li&gt;Choose &quot;Save as PDF&quot; and specify the destination&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;This process will create a new PDF without password protection.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;Merging_PDFs&quot;&gt;Merging PDFs&lt;&#x2F;h2&gt;
&lt;p&gt;While this can be done with &lt;code&gt;Ghostscript&lt;&#x2F;code&gt; (mentioned later), we&#x27;ll use &lt;code&gt;pdftk&lt;&#x2F;code&gt; for its advantages:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Preserves PDF internal structure (table of contents, bookmarks, links, etc.)&lt;&#x2F;li&gt;
&lt;li&gt;Operates at the binary level, preventing quality degradation&lt;&#x2F;li&gt;
&lt;li&gt;(Although not relevant for this case) Offers flexible operations like page rotation and reordering&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Here&#x27;s how to merge PDFs:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# Install pdftk (on Mac)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;brew&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; install pdftk-java&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# Merge PDFs&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;pdftk&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; input1.pdf input2.pdf cat output merged.pdf&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;PDF_Optimization&quot;&gt;PDF Optimization&lt;&#x2F;h2&gt;
&lt;p&gt;After merging, I found that the file size exceeded 40MB, which was too large to upload to MLIT&#x27;s DIPS2.0 (Drone&#x2F;UAS Information Platform System).&lt;&#x2F;p&gt;
&lt;p&gt;To resolve this, I used Ghostscript for optimization:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# Install Ghostscript (on Mac)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;brew&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; install ghostscript&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# Optimize PDF&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;gs&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; -sDEVICE=pdfwrite -dCompatibilityLevel=1.4 -dPDFSETTINGS=&#x2F;screen -dNOPAUSE -dQUIET -dBATCH -sOutputFile=output.pdf input.pdf&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The &lt;code&gt;-dPDFSETTINGS&lt;&#x2F;code&gt; option allows you to adjust the compression level:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;&#x2F;screen&lt;&#x2F;code&gt;: For screen display (72dpi) - smallest file size&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;&#x2F;ebook&lt;&#x2F;code&gt;: For e-books (150dpi) - balanced compression&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;&#x2F;printer&lt;&#x2F;code&gt;: For printing (300dpi)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;&#x2F;prepress&lt;&#x2F;code&gt;: For high-quality printing (highest quality)&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;Making_PDF_Searchable&quot;&gt;Making PDF Searchable&lt;&#x2F;h2&gt;
&lt;p&gt;Scanned PDFs aren&#x27;t searchable. Use these Linux&#x2F;Mac commands for OCR instead of expensive software:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;brew&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; install ocrmypdf&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;brew&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; install tesseract-lang&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# OCR with image optimization&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;ocrmypdf&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; -l jpn --optimize&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 3&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; input.pdf output.pdf&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;Creating_Table_of_contents&quot;&gt;Creating Table of contents&lt;&#x2F;h2&gt;
&lt;p&gt;Scanned PDFs often lack a table of contents. Instead of buying expensive PDF software, use these Linux&#x2F;Mac commands:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# Install pdftk (on Mac)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;brew&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; install pdftk-java&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# Extract metadata&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;pdftk&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; input.pdf dump_data_utf8&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; &amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; metadata.txt&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Open metadata.txt in your editor and add bookmark locations in this format:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;BookmarkBegin&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;BookmarkTitle: Chapter 1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;BookmarkLevel: 1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;BookmarkPageNumber: 1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;BookmarkBegin&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;BookmarkTitle: Chapter 2&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;BookmarkLevel: 1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;BookmarkPageNumber: 10&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Then apply the metadata to create a PDF with a table of contents:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# Apply edited metadata&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;pdftk&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; input.pdf update_info_utf8 metadata.txt output output.pdf&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;Conclusion&quot;&gt;Conclusion&lt;&#x2F;h2&gt;
&lt;p&gt;With these steps, I successfully optimized the PDF and completed the drone registration.&lt;&#x2F;p&gt;
&lt;p&gt;However, it seems rather inefficient to require individual manual submissions for DJI drones, which are widely used. This feels like typical bureaucratic red tape.&lt;&#x2F;p&gt;
&lt;p&gt;Finally, while this may only be relevant for Japanese users, I&#x27;m sharing the prepared DJI Neo manual that meets DIPS2.0 requirements here: &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;e.pcloud.link&#x2F;publink&#x2F;show?code=XZHwGwZuCQmrRb6SFHGinz8MJe1akHv9dF7&quot;&gt;Download&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
</content>
        <summary type="html">I recently purchased a DJI Neo drone, and in Japan, it&#x27;s mandatory to register your drone with the Ministry of Land, Infrastructure, Transport and Tourism (MLIT). During registration, you need to submit a user manual that includes both handling instructions and specifications. However, the DJI Neo manual only contains references to specifications on DJI&#x27;s website. Therefore, for the registration, I needed to merge the user manual with the specifications from the website.</summary>
        </entry><entry xml:lang="en">
        <title>A Failed Experiment: Using OpenCV to Read Printed Dates from Scanned Photos</title>
        <published>2025-01-06T00:00:00+00:00</published>
        <updated>2025-01-06T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2025/01/a-failed-experiment-using-opencv/" type="text/html"/>
        <id>https://codedchords.dev/blog/2025/01/a-failed-experiment-using-opencv/</id>
        
            <content type="html">&lt;h3 id=&quot;Organizing_Old_Photographs&quot;&gt;Organizing Old Photographs&lt;&#x2F;h3&gt;
&lt;p&gt;I recently purchased a scanner at the end of the year to digitize old photographs. The photographs have dates printed on them, and I&#x27;ve been manually setting these dates in the EXIF information using ExifTool.&lt;&#x2F;p&gt;
&lt;p&gt;I use Hazel to organize image files, and I&#x27;ve already created a tool that updates file creation dates that Hazel can read with the shooting dates from EXIF data. However, since setting EXIF information manually is time-consuming, I explored the possibility of automating this process using OpenCV.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;Date_Reading_Tool&quot;&gt;Date Reading Tool&lt;&#x2F;h3&gt;
&lt;p&gt;Below is a script that uses OpenCV to read dates from images and set them using ExifTool.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;python&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;#!&#x2F;usr&#x2F;bin&#x2F;env python3&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;from&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; datetime&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; import&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; datetime&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-python&quot;&gt;def&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; preprocess_image&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt;image_path&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;):&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;    &amp;quot;&amp;quot;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;    Extract and process the date stamp portion from the image&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;    &amp;quot;&amp;quot;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;    # Load image&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    img&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; cv2&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;imread&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;image_path&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    height&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; width&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; img&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-indexed-name z-python&quot;&gt;shape&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;2&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;    # Crop the bottom right region&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    x1&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-python&quot;&gt; int&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;width&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; *&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 0.65&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    y1&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-python&quot;&gt; int&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;height&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; *&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 0.75&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    cropped&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-indexed-name z-python&quot;&gt; img&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-item-access z-python&quot;&gt;y1&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-item-access z-python&quot;&gt;height&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-item-access z-python&quot;&gt; x1&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-item-access z-python&quot;&gt;width&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;    # Split channels&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    b&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; g&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; r&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; cv2&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;split&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;cropped&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;    # Enhance red channel&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    red_emphasis&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; cv2&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;subtract&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;r&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt; cv2&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;max&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;b&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt; g&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;))&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;    # Enhance contrast using CLAHE&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    clahe&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; cv2&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;createCLAHE&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt;clipLimit&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;3.0&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt; tileGridSize&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;8&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;8&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;))&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    enhanced&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; clahe&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;apply&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;red_emphasis&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;    # Strong thresholding&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    _&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; binary&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; cv2&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;threshold&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;enhanced&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 30&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 255&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt; cv2&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;THRESH_BINARY&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;    # Remove noise&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    kernel&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; np&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;ones&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;((&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;2&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;2&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;),&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt; np&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;uint8&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    cleaned&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; cv2&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;morphologyEx&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;binary&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt; cv2&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;MORPH_OPEN&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt; kernel&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;    # Detect and filter contours&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    contours&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; _&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; cv2&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;findContours&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;cleaned&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt; cv2&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;RETR_EXTERNAL&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt; cv2&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;CHAIN_APPROX_SIMPLE&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;    # Filter by area&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    mask&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; np&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;zeros_like&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;cleaned&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    min_area&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 10&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    max_area&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 500&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-control z-flow z-python&quot;&gt;    for&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; contour&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-control z-flow z-python&quot;&gt; in&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; contours&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;        area&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; cv2&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;contourArea&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;contour&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-control z-flow z-python&quot;&gt;        if&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; min_area&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; &amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; area&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; &amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; max_area&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;            cv2&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;drawContours&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;mask&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;, [&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;contour&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;],&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; -&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;1&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;, (&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;255&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;),&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; -&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;1&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;    # Resize to 4x&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    result&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; cv2&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;resize&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;mask&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language z-python&quot;&gt; None&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt; fx&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;4&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt; fy&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;4&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt; interpolation&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;cv2&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;INTER_CUBIC&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;    # Save debug images&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    debug_dir&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; os&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;path&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;join&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;os&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;path&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;dirname&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;image_path&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;),&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;#39;debug&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    os&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;makedirs&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;debug_dir&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt; exist_ok&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language z-python&quot;&gt;True&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    basename&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; os&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;path&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;basename&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;image_path&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    cv2&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;imwrite&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;os&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;path&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;join&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;debug_dir&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-string z-python&quot;&gt; f&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&amp;#39;cropped_&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-format z-placeholder z-other z-python&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;basename&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-format z-placeholder z-other z-python&quot;&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;),&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt; cropped&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    cv2&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;imwrite&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;os&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;path&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;join&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;debug_dir&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-string z-python&quot;&gt; f&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&amp;#39;red_emphasis_&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-format z-placeholder z-other z-python&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;basename&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-format z-placeholder z-other z-python&quot;&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;),&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt; red_emphasis&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    cv2&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;imwrite&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;os&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;path&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;join&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;debug_dir&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-string z-python&quot;&gt; f&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&amp;#39;enhanced_&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-format z-placeholder z-other z-python&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;basename&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-format z-placeholder z-other z-python&quot;&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;),&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt; enhanced&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    cv2&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;imwrite&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;os&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;path&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;join&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;debug_dir&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-string z-python&quot;&gt; f&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&amp;#39;binary_&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-format z-placeholder z-other z-python&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;basename&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-format z-placeholder z-other z-python&quot;&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;),&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt; binary&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    cv2&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;imwrite&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;os&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;path&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;join&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;debug_dir&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-string z-python&quot;&gt; f&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&amp;#39;result_&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-format z-placeholder z-other z-python&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;basename&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-format z-placeholder z-other z-python&quot;&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;),&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt; result&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-control z-flow z-python&quot;&gt;    return&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; result&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-python&quot;&gt;def&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; extract_date_from_image&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt;image_path&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;):&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;    &amp;quot;&amp;quot;&amp;quot;Extract date from image using OCR&amp;quot;&amp;quot;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;    # Preprocess image&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    processed_image&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt; preprocess_image&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;image_path&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;    # OCR configuration for single line text&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    custom_configs&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; [&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;        &amp;#39;--psm 6 -c tessedit_char_whitelist=&amp;quot;0123456789&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt;\&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt; &amp;quot;&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;  # Uniform text block&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;        &amp;#39;--psm 7 -c tessedit_char_whitelist=&amp;quot;0123456789&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt;\&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt; &amp;quot;&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;  # Single text line&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;        &amp;#39;--psm 8 -c tessedit_char_whitelist=&amp;quot;0123456789&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt;\&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt; &amp;quot;&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;  # Single word&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;        &amp;#39;--psm 10 -c tessedit_char_whitelist=&amp;quot;0123456789&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt;\&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt; &amp;quot;&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;  # Single character&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    ]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-control z-flow z-python&quot;&gt;    for&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; config&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-control z-flow z-python&quot;&gt; in&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; custom_configs&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;        # Run OCR&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;        text&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; pytesseract&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;image_to_string&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;processed_image&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt; config&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;config&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;        text&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; text&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;strip&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-function z-builtin z-python&quot;&gt;        print&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-string z-python&quot;&gt;f&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&amp;quot;OCR result (config=&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-format z-placeholder z-other z-python&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;config&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-format z-placeholder z-other z-python&quot;&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;): [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-format z-placeholder z-other z-python&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;text&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-format z-placeholder z-other z-python&quot;&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;]&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;        # Normalize spaces&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;        text&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt; &amp;#39; &amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;join&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;text&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;split&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;())&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;        # Simple pattern matching&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;        pattern&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-string z-python&quot;&gt; r&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-quantifier z-regexp&quot;&gt;?&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;\d&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-quantifier z-regexp&quot;&gt;{2}&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;\s&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-quantifier z-regexp&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;\d&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-quantifier z-regexp&quot;&gt;{1,2}&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;\s&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-quantifier z-regexp&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;\d&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-quantifier z-regexp&quot;&gt;{1,2}&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;        match&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; re&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;search&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;pattern&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt; text&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-control z-flow z-python&quot;&gt;        if&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; match&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-control z-flow z-python&quot;&gt;            try&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;                year&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-python&quot;&gt; int&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;match&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;group&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;1&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;))&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;                month&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-python&quot;&gt; int&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;match&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;group&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;2&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;))&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;                day&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-python&quot;&gt; int&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;match&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;group&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;3&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;))&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;                # Handle 2000s&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;                year&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 2000&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; +&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; year&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-control z-flow z-python&quot;&gt; if&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; year&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; &amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 50&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-control z-flow z-python&quot;&gt; else&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 1900&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; +&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; year&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-control z-flow z-python&quot;&gt;                if&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 1&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; &amp;lt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; month&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; &amp;lt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 12&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-logical z-python&quot;&gt; and&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 1&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; &amp;lt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; day&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; &amp;lt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 31&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-control z-flow z-python&quot;&gt;                    return&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt; datetime&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;year&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt; month&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt; day&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-control z-flow z-python&quot;&gt;            except&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-exception z-python&quot;&gt; ValueError&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-control z-flow z-python&quot;&gt;                continue&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-control z-flow z-python&quot;&gt;    return&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language z-python&quot;&gt; None&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-python&quot;&gt;def&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; set_exif_date&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt;image_path&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt; date&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;):&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;    &amp;quot;&amp;quot;&amp;quot;Set EXIF date information using ExifTool&amp;quot;&amp;quot;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-control z-flow z-python z-keyword z-operator z-logical z-python&quot;&gt;    if not&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; date&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-function z-builtin z-python&quot;&gt;        print&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-string z-python&quot;&gt;f&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&amp;quot;No date found in: &lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-format z-placeholder z-other z-python&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;image_path&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-format z-placeholder z-other z-python&quot;&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-control z-flow z-python&quot;&gt;        return&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language z-python&quot;&gt; False&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    date_str&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; date&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;strftime&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;%Y:%m:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-format z-placeholder z-other z-python&quot;&gt;%d&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;    # EXIF tags to set&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    exif_tags&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; [&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;        &amp;quot;DateTimeOriginal&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;        &amp;quot;CreateDate&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;        &amp;quot;ModifyDate&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    ]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    command&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;exiftool&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;-overwrite_original_in_place&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-control z-flow z-python&quot;&gt;    for&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; tag&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-control z-flow z-python&quot;&gt; in&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; exif_tags&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;        command&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;extend&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;([&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-string z-python&quot;&gt;f&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&amp;quot;-&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-format z-placeholder z-other z-python&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;tag&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-format z-placeholder z-other z-python&quot;&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-format z-placeholder z-other z-python&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;date_str&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-format z-placeholder z-other z-python&quot;&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;])&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    command&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;append&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;image_path&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-control z-flow z-python&quot;&gt;    try&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;        subprocess&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;run&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;command&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt; check&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language z-python&quot;&gt;True&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt; capture_output&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language z-python&quot;&gt;True&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-function z-builtin z-python&quot;&gt;        print&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-string z-python&quot;&gt;f&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&amp;quot;Date set successfully: &lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-format z-placeholder z-other z-python&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;image_path&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-format z-placeholder z-other z-python&quot;&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; -&amp;gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-format z-placeholder z-other z-python&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;date_str&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-format z-placeholder z-other z-python&quot;&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-control z-flow z-python&quot;&gt;        return&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language z-python&quot;&gt; True&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-control z-flow z-python&quot;&gt;    except&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; subprocess&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;CalledProcessError&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-control z-flow z-python&quot;&gt; as&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; e&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-function z-builtin z-python&quot;&gt;        print&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-string z-python&quot;&gt;f&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&amp;quot;Failed to set EXIF information: &lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-format z-placeholder z-other z-python&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;e&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-format z-placeholder z-other z-python&quot;&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-control z-flow z-python&quot;&gt;        return&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language z-python&quot;&gt; False&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-python&quot;&gt;def&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; process_images&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt;directory&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;):&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;    &amp;quot;&amp;quot;&amp;quot;Process all images in the specified directory&amp;quot;&amp;quot;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    processed&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    failed&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-control z-flow z-python&quot;&gt;    for&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; filename&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-control z-flow z-python&quot;&gt; in&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; os&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;listdir&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;directory&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;):&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-control z-flow z-python&quot;&gt;        if&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; filename&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;lower&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;().&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;endswith&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;((&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;#39;.png&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;#39;.jpg&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;#39;.jpeg&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)):&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;            image_path&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; os&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;path&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;join&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;directory&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt; filename&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;            date&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt; extract_date_from_image&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;image_path&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-control z-flow z-python&quot;&gt;            if&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt; set_exif_date&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;image_path&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt; date&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;):&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;                processed&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; +=&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-control z-flow z-python&quot;&gt;            else&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;                failed&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; +=&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-function z-builtin z-python&quot;&gt;    print&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-string z-python&quot;&gt;f&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;Processing complete:&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-function z-builtin z-python&quot;&gt;    print&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-string z-python&quot;&gt;f&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&amp;quot;Success: &lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-format z-placeholder z-other z-python&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;processed&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-format z-placeholder z-other z-python&quot;&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-function z-builtin z-python&quot;&gt;    print&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-string z-python&quot;&gt;f&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&amp;quot;Failed: &lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-format z-placeholder z-other z-python&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;failed&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-format z-placeholder z-other z-python&quot;&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-python&quot;&gt;def&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; main&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;():&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-control z-flow z-python&quot;&gt;    if&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-builtin z-python&quot;&gt; len&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;sys&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;argv&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; !=&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 2&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-function z-builtin z-python&quot;&gt;        print&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;Usage: photodate &amp;lt;image_directory&amp;gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;        sys&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;exit&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;1&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    directory&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; sys&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-indexed-name z-python&quot;&gt;argv&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;1&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-control z-flow z-python z-keyword z-operator z-logical z-python&quot;&gt;    if not&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; os&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;path&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;isdir&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;directory&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;):&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-function z-builtin z-python&quot;&gt;        print&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;Specified path is not a valid directory&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;        sys&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;exit&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;1&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;    process_images&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;directory&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-control z-flow z-python&quot;&gt;if&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-variable z-magic z-python&quot;&gt; __name__&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; ==&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;__main__&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;    main&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;Results&quot;&gt;Results&lt;&#x2F;h3&gt;
&lt;p&gt;I tested the script on 27 scanned photographs.&lt;&#x2F;p&gt;
&lt;p&gt;Out of 27 images, the script only detected dates in 4 images, and among those, only 1 date was correctly recognized.&lt;&#x2F;p&gt;
&lt;p&gt;Well, this isn&#x27;t practical enough to use.&lt;&#x2F;p&gt;
</content>
        <summary type="html">I recently purchased a scanner and was challenged to see if I could capture the shooting date from the images when digitizing old photos that have dates printed on them.</summary>
        </entry><entry xml:lang="en">
        <title>店舗のSNS依存 - 顧客に届かない情報発信</title>
        <published>2025-01-04T00:00:00+00:00</published>
        <updated>2025-01-04T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2025/01/sns/" type="text/html"/>
        <id>https://codedchords.dev/blog/2025/01/sns/</id>
        
            <content type="html">&lt;h3 id=&quot;1._なぜ店舗はSNSのみで情報発信するのか&quot;&gt;1. なぜ店舗はSNSのみで情報発信するのか&lt;&#x2F;h3&gt;
&lt;p&gt;店舗がSNSでのみ情報発信することについて、考えられる理由と問題点を分析してみましょう。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;運営効率&lt;&#x2F;strong&gt; - SNSでの投稿は迅速で簡単。ウェブサイトやその他の通信チャネルの管理と比較すると、よりコスト効率が良い。&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;ターゲット層の認識の誤り&lt;&#x2F;strong&gt; - お店が主に若い世代をターゲットにしている場合、SNSでの発信で十分だと考えているかも。しかし、これは若い世代でさえも問題のある仮定。&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;リソースの制限&lt;&#x2F;strong&gt; - 小規模ビジネスでは、複数の通信チャネルを管理する人員や時間が不足している可能性がある。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;しかし、もっとも大きな理由は店舗スタッフの&lt;strong&gt;ITリテラシーの低さ&lt;&#x2F;strong&gt;が理由でしょう。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;どこで発信すると、誰に届くか理解していない&lt;&#x2F;li&gt;
&lt;li&gt;WordPressなどのサイト運営する能力がなく、SNSのようにプライベートの延長で他者のプラットフォームに依存した情報発信しかできない&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;以前は多くのSNSがユーザー以外にもオープンでしたが、TwitterやFacebook、Instagramを見ればわかるようにコンテンツ閲覧にはユーザー登録を要求するSNSが多くなってきたため、SNSで発信する情報がSNS外のユーザーに届かないということがより顕著になってきました。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;2._SNSプラットフォーム依存のリスク&quot;&gt;2. SNSプラットフォーム依存のリスク&lt;&#x2F;h3&gt;
&lt;p&gt;店舗情報発信でのSNS利用は非常に手軽ですが、次のようなリスクもあります。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;高齢者やプライバシーを重視しSNSを利用しない賢者、特定のSNSを利用していない顧客など潜在的な顧客に情報が届かず、ビジネスチャンスを逃している可能性がある。&lt;&#x2F;li&gt;
&lt;li&gt;SNS外で情報が見えないため、検索エンジンの視認性が欠如し、ニーズを持った潜在的な顧客を逃す可能性がある。&lt;&#x2F;li&gt;
&lt;li&gt;SNSでは投稿の表示のアルゴリズムをプラットフォーマーが握っているため、店舗で管理が必須。このため有利に働くことも有れば、必要な顧客層の情報が届かないリスクもある。&lt;&#x2F;li&gt;
&lt;li&gt;プラットフォームのサービス終了、アカウント停止など、店舗の情報発信が不能となるリスクが常にある。&lt;&#x2F;li&gt;
&lt;li&gt;自社サイトを持たないことによりブランディングやビジネスイメージの確立が困難となるリスクがある。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;まとめ&quot;&gt;まとめ&lt;&#x2F;h3&gt;
&lt;p&gt;以前は自社サイトを持ちつつSNSでも情報発信するスタイルが一般的でしたが、昨今はSNSでの情報発信を重視しすぎる店舗が増えたように感じます。&lt;&#x2F;p&gt;
&lt;p&gt;効果的な情報発信戦略としては、以下のようなマルチチャネルアプローチが望ましいでしょう。&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;基本的な情報発信プラットフォーム&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;自社ウェブサイト（基本情報、営業時間、アクセス）&lt;&#x2F;li&gt;
&lt;li&gt;店頭での掲示&lt;&#x2F;li&gt;
&lt;li&gt;Googleビジネスプロフィール&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;補完的な情報発信チャネル&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;SNS（Instagram、Facebook等）&lt;&#x2F;li&gt;
&lt;li&gt;メールマガジン&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;このように複数のチャネルを組み合わせることで、より幅広い顧客層にリーチでき、プラットフォーム依存のリスクも軽減できます。重要なのは、それぞれのチャネルの特性を理解し、効果的に活用することです。&lt;&#x2F;p&gt;
&lt;p&gt;どうでもいいけど、近くのパン屋の営業時間くらい、SNSに登録しなくてもわかるようにしてほしい。&lt;&#x2F;p&gt;
</content>
        <summary type="html">最近営業日の告知をInstgramやfacebookにしか掲載しないお店があるが、一体どういうつもりなんだろう。Instagramを使っていない客がいるとか想像できないのだろうか？</summary>
        </entry><entry xml:lang="en">
        <title>LogSeq at a Glance: An Overview for Beginners</title>
        <published>2025-01-01T00:00:00+00:00</published>
        <updated>2025-01-01T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2025/01/logseq/" type="text/html"/>
        <id>https://codedchords.dev/blog/2025/01/logseq/</id>
        
            <content type="html"> &lt;details&gt;
  &lt;summary&gt;Table of Contents&lt;&#x2F;summary&gt;
  &lt;!-- toc --&gt;
  &lt;&#x2F;details&gt;
&lt;h2 id=&quot;はじめに&quot;&gt;はじめに&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;LogSeqとは何か、シンプルな説明&quot;&gt;LogSeqとは何か、シンプルな説明&lt;&#x2F;h3&gt;
&lt;p&gt;LogSeqは、あなたの考えやアイデア、メモを自由に書き留め、それらをつなぎ合わせることができるデジタルノートアプリです。紙のノートとは違い、書いた内容を後から簡単に整理したり、関連する情報どうしをリンクでつなげたりできます。&lt;&#x2F;p&gt;
&lt;p&gt;特徴的なのは、以下の3つのポイントです。&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;箇条書きベースで書ける&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;考えたことを思いつくままメモできる&lt;&#x2F;li&gt;
&lt;li&gt;後から簡単に整理できる&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;日付ごとにページが自動で作られる&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;日記のように、その日のことを記録できる&lt;&#x2F;li&gt;
&lt;li&gt;カレンダーのように過去の記録を見返せる&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;ページ同士をつなげられる&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;関連する情報どうしを簡単にリンクできる&lt;&#x2F;li&gt;
&lt;li&gt;新しい気づきや発見を見つけやすい&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;h3 id=&quot;なぜLogSeqが便利なのか&quot;&gt;なぜLogSeqが便利なのか&lt;&#x2F;h3&gt;
&lt;p&gt;LogSeqが便利な理由は、私たちの脳の働き方と合わせた設計にあります。&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;思考の自然な流れを妨げない&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;思いついたことを、その場でさっと書き留められる&lt;&#x2F;li&gt;
&lt;li&gt;後でどこに書いたか探すことを気にせず、まずメモできる&lt;&#x2F;li&gt;
&lt;li&gt;整理は後からでもできる&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;情報同士のつながりを自然に作れる&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;関連する情報を&lt;code&gt;[[リンク]]&lt;&#x2F;code&gt;で簡単につなげられる&lt;&#x2F;li&gt;
&lt;li&gt;一度つないだ情報は、双方向から見つけられる&lt;&#x2F;li&gt;
&lt;li&gt;気づかなかった情報のつながりが自然と見えてくる&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;記憶と振り返りをサポート&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;日付ごとのページが自動で作られるので、いつ何を考えたかが残る&lt;&#x2F;li&gt;
&lt;li&gt;過去の記録が自然とタイムライン化される&lt;&#x2F;li&gt;
&lt;li&gt;定期的な振り返りが簡単にできる&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;知識が育っていく&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;書いた内容は単なる記録として終わらない&lt;&#x2F;li&gt;
&lt;li&gt;新しい情報を追加するたびに、既存の知識とつながっていく&lt;&#x2F;li&gt;
&lt;li&gt;それによって新しい発見や気づきが生まれる&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;つまり、LogSeqは「とりあえずメモ」から始めて、そこから自然と「つながりのある知識」を育てていけるツールなのです。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;LogSeqの基本的な使い方&quot;&gt;LogSeqの基本的な使い方&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;最初の画面の見方&quot;&gt;最初の画面の見方&lt;&#x2F;h3&gt;
&lt;p&gt;LogSeqを開くと、シンプルな画面が表示されます。画面の構成を理解しましょう。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;左側のサイドバー&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;ジャーナル（日付ごとのページ）へのリンク&lt;&#x2F;li&gt;
&lt;li&gt;お気に入りページの一覧&lt;&#x2F;li&gt;
&lt;li&gt;全てのページ一覧&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;メイン画面&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;現在の日付のページが自動で開&lt;&#x2F;li&gt;
&lt;li&gt;ここに自由に文章を書いていく&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;右側のサイドバー&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;開いているページに関連する情報が表示&lt;&#x2F;li&gt;
&lt;li&gt;リンクされているページの一覧なども表示&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;新しいページの作り方&quot;&gt;新しいページの作り方&lt;&#x2F;h3&gt;
&lt;p&gt;新しいページを作るには2つの方法があります。&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;直接作成する方法&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;画面上部の検索バーに新しいページ名を入力&lt;&#x2F;li&gt;
&lt;li&gt;エンターキーを押すと、新しいページが作られる&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;リンクから作る方法&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;文章の中に&lt;code&gt;[[新しいページ名]]&lt;&#x2F;code&gt;と書く&lt;&#x2F;li&gt;
&lt;li&gt;自動的にリンクが作られ、クリックで新しいページを作られる&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;h3 id=&quot;Markdownで記入する&quot;&gt;Markdownで記入する&lt;&#x2F;h3&gt;
&lt;p&gt;LogSeqでは、Markdownという書き方を使います。難しく考える必要はありません。
以下のような基本的な書き方を覚えましょう。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;見出しの書き方&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;markdown&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-text&quot;&gt;大見出し&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-heading z-markdown z-heading z-\31  z-markdown&quot;&gt;# 中見出し&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-heading z-markdown z-heading z-\32  z-markdown&quot;&gt;## 小見出し&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;strong&gt;文字の装飾&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;markdown&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;_&lt;&#x2F;span&gt;&lt;span class=&quot;z-markup z-italic&quot;&gt;斜体で書く&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;_&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;**&lt;&#x2F;span&gt;&lt;span class=&quot;z-markup z-bold&quot;&gt;太字で書く&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;**&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;~~&lt;&#x2F;span&gt;&lt;span class=&quot;z-markup z-strikethrough&quot;&gt;打ち消し線&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;~~&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;strong&gt;箇条書き&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;markdown&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-list z-begin z-markdown&quot;&gt;-&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt; 箇条書き1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-list z-begin z-markdown&quot;&gt;  -&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt; 箇条書き1-1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-list z-begin z-markdown&quot;&gt;  -&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt; 箇条書き1-2&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-list z-begin z-markdown&quot;&gt;-&lt;&#x2F;span&gt;&lt;span class=&quot;z-text&quot;&gt; 箇条書き2&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;これらの書き方は、実際に使いながら少しずつ覚えていけば大丈夫です。最初は普通の文章を書くところから始めましょう。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;日々のノート作成の基本&quot;&gt;日々のノート作成の基本&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;箇条書きの書き方&quot;&gt;箇条書きの書き方&lt;&#x2F;h3&gt;
&lt;p&gt;LogSeqでは、箇条書きを基本としてノートを作成します。箇条書きには、以下のような特徴があります。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;基本の書き方&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;行頭に「-」（ハイフン）と半角スペースを入力&lt;&#x2F;li&gt;
&lt;li&gt;Enterキーを押すと、自動的に次の箇条書きが始まる&lt;&#x2F;li&gt;
&lt;li&gt;Tabキーで階層を下げる（字下げ）&lt;&#x2F;li&gt;
&lt;li&gt;Shift + Tabで階層を上げる&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;箇条書きのコツ&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;1つの項目は短めに書く&lt;&#x2F;li&gt;
&lt;li&gt;詳しい説明が必要な場合は、階層を下げて書く&lt;&#x2F;li&gt;
&lt;li&gt;関連する内容は、同じ階層にまとめる&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;日付ページの使い方&quot;&gt;日付ページの使い方&lt;&#x2F;h3&gt;
&lt;p&gt;LogSeqでは、毎日自動的に日付のページ（ジャーナル）が作られます。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;日付ページの特徴&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;起動時に自動的に今日の日付のページが開く&lt;&#x2F;li&gt;
&lt;li&gt;左サイドバーの「Journals」から過去の日付を開ける&lt;&#x2F;li&gt;
&lt;li&gt;日付ページには、その日に考えたことや行ったことを自由に書ける&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;効果的な使い方&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;朝：今日やることを箇条書きで書き出す&lt;&#x2F;li&gt;
&lt;li&gt;日中：気づいたことや考えたことをメモ&lt;&#x2F;li&gt;
&lt;li&gt;夜：その日の振り返りを書く&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;タグの付け方と活用法&quot;&gt;タグの付け方と活用法&lt;&#x2F;h3&gt;
&lt;p&gt;タグは情報の整理と検索を助ける強力なツールです。ページリンクと組み合わせることで、より効果的な知識管理が可能になります。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;タグの基本&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;単語の前に「#」（ハッシュ）を付ける&lt;&#x2F;li&gt;
&lt;li&gt;例：#勉強 #アイデア #ToDo&lt;&#x2F;li&gt;
&lt;li&gt;スペースを含む場合は「&lt;code&gt;#[[読書メモ]]&lt;&#x2F;code&gt;」のように[[]]で囲む&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;タグとページリンクの特徴と使い分け&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;タグ（#）の特徴&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;複数のページに共通する「性質」を示すのに適している&lt;&#x2F;li&gt;
&lt;li&gt;一覧表示やフィルタリングが簡単&lt;&#x2F;li&gt;
&lt;li&gt;例：#未完了、#重要、#要復習&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;ページリンク([[]])の特徴&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;特定の「主題」についての詳細な記述に適している&lt;&#x2F;li&gt;
&lt;li&gt;概念間の関係性を表現しやすい&lt;&#x2F;li&gt;
&lt;li&gt;例：&lt;code&gt;[[数学]]&lt;&#x2F;code&gt;、&lt;code&gt;[[微分]]&lt;&#x2F;code&gt;、&lt;code&gt;[[Newton]]&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;効果的な併用方法&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;主題と性質を組み合わせる
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;[[微分]]&lt;&#x2F;code&gt; のページに #数学 #要復習を付ける&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;[[読書記録]]&lt;&#x2F;code&gt; のページに #継続中 #インプットを付ける&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;概念の関係性を示す
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;[[微分]]&lt;&#x2F;code&gt;のページで &lt;code&gt;[[極限]]&lt;&#x2F;code&gt; と &lt;code&gt;[[関数]]&lt;&#x2F;code&gt; を参照しつつ、#数学を付ける&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;[[Newton]]&lt;&#x2F;code&gt;のページで &lt;code&gt;[[力学]]&lt;&#x2F;code&gt; を参照しつつ、#物理学者を付ける&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;このように、タグとページリンクはそれぞれの特徴を活かして使うことで、より効率的な知識管理が可能になります。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;知識のつながりを作る&quot;&gt;知識のつながりを作る&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;ページ間のリンクの作り方&quot;&gt;ページ間のリンクの作り方&lt;&#x2F;h3&gt;
&lt;p&gt;LogSeqの強力な特徴は、ページ同士をつなげられることです。知識と知識を結びつけることで、新しい気づきが生まれやすくなります。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;基本的なリンクの作り方&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;[[ページ名]]&lt;&#x2F;code&gt; と入力する（&lt;code&gt;[[&lt;&#x2F;code&gt;と&lt;code&gt;]]&lt;&#x2F;code&gt;で囲む）&lt;&#x2F;li&gt;
&lt;li&gt;リンク先のページがなければ、自動的に新しいページが作られる&lt;&#x2F;li&gt;
&lt;li&gt;エイリアスをつける場合：&lt;code&gt;[[ページ名]][表示したい文字]&lt;&#x2F;code&gt;
&lt;ul&gt;
&lt;li&gt;例：&lt;code&gt;[[アインシュタイン]][彼]&lt;&#x2F;code&gt;と書くと、「彼」と表示される&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;効果的なリンクの付け方&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;重要な概念や用語が出てきたらリンクにする&lt;&#x2F;li&gt;
&lt;li&gt;関連する話題が出てきたら積極的にリンクする&lt;&#x2F;li&gt;
&lt;li&gt;あとで詳しく書きたい内容があればリンクにする&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;バックリンクの概念と確認方法&quot;&gt;バックリンクの概念と確認方法&lt;&#x2F;h3&gt;
&lt;p&gt;バックリンクとは、「どのページからリンクされているか」を示す機能です。自動的に作られる双方向のつながりにより、知識の関係性が見えてきます。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;バックリンクの特徴&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;自動的に作られる（手動で作る必要はない）&lt;&#x2F;li&gt;
&lt;li&gt;右サイドバーに表示される&lt;&#x2F;li&gt;
&lt;li&gt;リンク元のページの該当部分が引用として表示される&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;バックリンクの活用法&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;関連する記述を後から発見できる&lt;&#x2F;li&gt;
&lt;li&gt;同じ概念が出てくる文脈を確認できる&lt;&#x2F;li&gt;
&lt;li&gt;知識のunexpectedな関連性に気づける&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;関連する情報のつながりを見つける方法&quot;&gt;関連する情報のつながりを見つける方法&lt;&#x2F;h3&gt;
&lt;p&gt;LogSeqには、知識のつながりを見つけるための様々な機能があります。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;グラフビュー&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;ページ間のつながりを視覚的に表示&lt;&#x2F;li&gt;
&lt;li&gt;右上のグラフアイコンをクリック&lt;&#x2F;li&gt;
&lt;li&gt;ノードをクリックすると関連するページに移動&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;検索機能の活用&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;キーワードで関連ページを検索&lt;&#x2F;li&gt;
&lt;li&gt;タグとページリンクを組み合わせて検索&lt;&#x2F;li&gt;
&lt;li&gt;日付範囲を指定して検索&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;知識のつながりを育てる方法&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;定期的にバックリンクを確認する&lt;&#x2F;li&gt;
&lt;li&gt;関連しそうなページを積極的にリンクする&lt;&#x2F;li&gt;
&lt;li&gt;グラフビューで全体の構造を確認する&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;このように、LogSeqでは知識同士を様々な方法でつなげることができます。つながりが増えるほど、新しい発見や気づきが生まれやすくなります。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;まとめ&quot;&gt;まとめ&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;日常的な使い方のおすすめパターン&quot;&gt;日常的な使い方のおすすめパターン&lt;&#x2F;h3&gt;
&lt;p&gt;LogSeqを効果的に活用するために、以下のような使い方がおすすめです。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;1日の基本的な流れ&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;朝：今日やることを箇条書きで書き出す&lt;&#x2F;li&gt;
&lt;li&gt;日中：思いついたことを &lt;code&gt;[[]]&lt;&#x2F;code&gt; でリンクしながらメモ&lt;&#x2F;li&gt;
&lt;li&gt;夜：その日の振り返りと、重要な項目に &lt;code&gt;#タグ&lt;&#x2F;code&gt; をつける&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;知識を育てる方法&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;気になる言葉は積極的に &lt;code&gt;[[]]&lt;&#x2F;code&gt; でリンク&lt;&#x2F;li&gt;
&lt;li&gt;関連する過去のメモは右サイドバーのバックリンクで確認&lt;&#x2F;li&gt;
&lt;li&gt;時々グラフビューを開いて知識の関係性を見直す&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;継続的な活用のコツ&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;完璧を目指さず、まずはメモを取ることから始める&lt;&#x2F;li&gt;
&lt;li&gt;少しずつ機能を試して、自分に合う使い方を見つける&lt;&#x2F;li&gt;
&lt;li&gt;定期的に過去のメモを見返して、知識をアップデート&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;困ったときの対処法&quot;&gt;困ったときの対処法&lt;&#x2F;h3&gt;
&lt;p&gt;LogSeqを使っていて困ったときは、以下の方法を試してみましょう。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;書き方を忘れたとき&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Markdownの基本：&lt;code&gt;#&lt;&#x2F;code&gt; で見出し、&lt;code&gt;-&lt;&#x2F;code&gt; で箇条書き&lt;&#x2F;li&gt;
&lt;li&gt;リンクとタグ：&lt;code&gt;[[ページ名]]&lt;&#x2F;code&gt; と &lt;code&gt;#タグ名&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;これらは画面下部のヘルプアイコンでいつでも確認可能&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;情報が見つからないとき&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;検索バーに関連するキーワードを入力&lt;&#x2F;li&gt;
&lt;li&gt;タグで絞り込み検索&lt;&#x2F;li&gt;
&lt;li&gt;グラフビューで関連ページを探す&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;整理が必要と感じたとき&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;関連する情報を新しいページにまとめる&lt;&#x2F;li&gt;
&lt;li&gt;適切なタグをつけて分類する&lt;&#x2F;li&gt;
&lt;li&gt;不要になったメモは、アーカイブとしてタグ付け&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;LogSeqは、使い始めは普通のメモ帳として、慣れてきたら知識を育てるツールとして活用できます。一度にすべての機能を使いこなす必要はありません。自分のペースで、少しずつ使い方を広げていってください。&lt;&#x2F;p&gt;
</content>
        <summary type="html">I created this simple guide to LogSeq to help friends get started with the tool. Written in Japanese, this overview aims to help new users understand LogSeq&#x27;s key features and daily usage patterns from a bird&#x27;s-eye perspective.</summary>
        </entry><entry xml:lang="en">
        <title>A Command to Sync EXIF Data with File System Timestamps</title>
        <published>2024-12-30T00:00:00+00:00</published>
        <updated>2024-12-30T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2024/12/exif-tool/" type="text/html"/>
        <id>https://codedchords.dev/blog/2024/12/exif-tool/</id>
        
            <content type="html">&lt;p&gt;The scanner&#x27;s performance has been impressive - it handled even my old San Francisco business trip photos from 2001 beautifully, producing crisp, clear scans.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;Setting_EXIF_Information&quot;&gt;Setting EXIF Information&lt;&#x2F;h2&gt;
&lt;p&gt;Unlike photos taken with a digital camera, scanned images don&#x27;t come with proper EXIF data. To preserve the actual capture dates of these photos, I used exiftool from the command line to set the correct EXIF information:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# Example: Setting the original capture date&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;exiftool&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;-DateTimeOriginal=2001:04:15 10:00:00&amp;quot; photo.jpg&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This command successfully embeds the correct capture date in the photo&#x27;s EXIF data.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;The_Photo_Organization&quot;&gt;The Photo Organization&lt;&#x2F;h2&gt;
&lt;p&gt;For managing my photo files, I rely on Hazel, a powerful file organization tool for Mac. Hazel offers some fantastic automation features:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Filtering based on file creation and modification dates&lt;&#x2F;li&gt;
&lt;li&gt;Automatic folder organization&lt;&#x2F;li&gt;
&lt;li&gt;Smart file renaming&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;However, Hazel has one limitation that&#x27;s been bugging me: it can&#x27;t directly read EXIF data. This means that even though I&#x27;ve carefully added the correct capture dates to the EXIF data, I can&#x27;t use this information for Hazel&#x27;s automated organization.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;The_Solution:_adj-photodate_Script&quot;&gt;The Solution: adj-photodate Script&lt;&#x2F;h2&gt;
&lt;p&gt;To bridge this gap, I created a script that syncs EXIF information with the file system timestamps (creation and modification dates). This enables Hazel to organize photos based on their actual capture dates.&lt;&#x2F;p&gt;
&lt;p&gt;The script provides the following features:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Syncs &lt;code&gt;DateTimeOriginal&lt;&#x2F;code&gt; from EXIF to file system timestamps&lt;&#x2F;li&gt;
&lt;li&gt;Includes a dry-run mode for previewing changes&lt;&#x2F;li&gt;
&lt;li&gt;Handles batch processing of multiple files&lt;&#x2F;li&gt;
&lt;li&gt;Supports recursive directory processing&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;Installation&quot;&gt;Installation&lt;&#x2F;h3&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Create a file named &quot;adj-photodate&quot; and paste the following script:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;gist.github.com&#x2F;yostos&#x2F;9c301b2831ad3e810cbb4131586687a7&quot;&gt;adj-photodate&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Make it executable:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;chmod&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; +x adj-photodate&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Optionally, move it to your path:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;cp&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; adj-photodate ~&#x2F;bin&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Dependencies:&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;ul&gt;
&lt;li&gt;bash shell&lt;&#x2F;li&gt;
&lt;li&gt;exiftool&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;Usage&quot;&gt;Usage&lt;&#x2F;h3&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# Process a single file&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;.&#x2F;adj-photodate&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; photo.jpg&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# Preview changes with dry-run&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;.&#x2F;adj-photodate&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; -n photo.jpg&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# Process all JPEG files in a directory recursively&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;.&#x2F;adj-photodate&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; -r ~&#x2F;Pictures&#x2F;Scanned&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;To see available options:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;.&#x2F;adj-photodate&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; --help&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;</content>
        <summary type="html">I recently embarked on a journey to digitize my old photographs. Since mypre-digital photos exist only as physical prints, I decided to invest in aPFU scanner to bring these memories into the digital age.</summary>
        </entry><entry xml:lang="en">
        <title>Berkeley Mono: A Worthy Successor to MonoLisa in My Terminal</title>
        <published>2024-12-19T00:00:00+00:00</published>
        <updated>2024-12-19T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2024/12/berkeley-mono/" type="text/html"/>
        <id>https://codedchords.dev/blog/2024/12/berkeley-mono/</id>
        
            <content type="html">&lt;p&gt;ずっとMacのターミナルでは&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.monolisa.dev&#x2F;&quot;&gt;MonoLisa&lt;&#x2F;a&gt;フォントを利用してきましたが、
&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;berkeleygraphics.com&#x2F;typefaces&#x2F;berkeley-mono&#x2F;&quot;&gt;Berkeley Mono&lt;&#x2F;a&gt;フォントに入れ替えました。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;MonoLisaフォントの課題&quot;&gt;MonoLisaフォントの課題&lt;&#x2F;h2&gt;
&lt;p&gt;MonoLisaフォントは紛らわしい文字の区別やリガチャのサポートなどコーディングをサポートするためのデザインがなされており読みやすいフォントで愛用していました。一部筆記体のようなデザインも気に入っていました。&lt;&#x2F;p&gt;
&lt;p&gt;ただし、次の2点が課題だと思っていました。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;読みやすさを考慮しているのだと思いますが、文字間隔が広すぎて間延びして逆にコードを把握しにくい。&lt;&#x2F;li&gt;
&lt;li&gt;ライセンス費用が割高でWebフォントまで入手しようとすると非常に高額になる。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;また、単純に飽きたということもあります。&lt;&#x2F;p&gt;
&lt;p&gt;Cascadia Next JPのプレビューが出ているので少し使ってみしたが、かなり文字間隔が狭く凝縮した印象です。MonoLisaのように文字間隔が広すぎるより、個人的は好みでした。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;Berkeley_Mono_を導入する&quot;&gt;Berkeley Mono を導入する&lt;&#x2F;h2&gt;
&lt;p&gt;Berkeley Monoは少し前に一部で話題になっていましたが、リガチャのサポートがなかったのでその時は見送りました。
ところが最近になって確認するとリガチャをサポートしたようだったので、購入しました。&lt;&#x2F;p&gt;
&lt;p&gt;紹介文には以下のように書かれています。&lt;&#x2F;p&gt;
&lt;blockquote cite=&quot;https:&#x2F;&#x2F;berkeleygraphics.com&#x2F;typefaces&#x2F;berkeley-mono&#x2F;&quot;&gt;
  Berkeley Mono is a love letter to the golden era of computing. The era that
  gave rise to a generation of people who celebrated automation and reveled in
  the joy of computing, when transistors replaced cogs, and machine-readable
  typefaces were developed, for when humans and machines truly interfaced on an
  unprecedented scale.
  &lt;footer&gt;
    &lt;cite&gt;
      Berkeley Graphics -{&quot; &quot;}
      &lt;a href=&quot;https:&#x2F;&#x2F;berkeleygraphics.com&#x2F;typefaces&#x2F;berkeley-mono&#x2F;&quot;&gt;
        Berkeley Mono
      &lt;&#x2F;a&gt;
    &lt;&#x2F;cite&gt;
  &lt;&#x2F;footer&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;確かにちょっと懐かしい「コンピューター」らしい文字のデザインです。&lt;&#x2F;p&gt;
&lt;p&gt;気に入っている点は、次の3点です。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;ちょうど良い文字間隔&lt;&#x2F;li&gt;
&lt;li&gt;スクエアなデザイン&lt;&#x2F;li&gt;
&lt;li&gt;買い切りでWebフォントまで含んでいる&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;特に文字間隔や高さが日本語フォントとバランス良いよいに思います。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;フォント比較&quot;&gt;フォント比較&lt;&#x2F;h2&gt;
&lt;p&gt;以下のスクリーンショットは、適当なプログラムCascadia Next &#x2F; MonoLisa &#x2F; Berkeley Monoを使って表示させた例です。&lt;&#x2F;p&gt;
&lt;!-- textlint-disable --&gt;
&lt;img
  src=&quot;https:&amp;#x2F;&amp;#x2F;codedchords.dev&amp;#x2F;blog&amp;#x2F;2024&amp;#x2F;12&amp;#x2F;berkeley-mono&amp;#x2F;fonts.jpg?h=dc626dd5229814723749&quot;
  alt=&quot;Fonts Comparison&quot; width=&quot;1800&quot; height=&quot;996&quot; loading=&quot;lazy&quot;
&#x2F;&gt;&lt;!-- textlint-enable --&gt;
&lt;p&gt;文字間隔の違いがよくわかると思います。&lt;&#x2F;p&gt;
</content>
        <summary type="html">ずっとMacのターミナルではMonoLisaフォントを利用してきましたが、Berkeley Monoフォントに入れ替えました。</summary>
        </entry><entry xml:lang="en">
        <title>The Ultimate Guide to RAW Development: Data-Driven Insights</title>
        <published>2024-11-25T00:00:00+00:00</published>
        <updated>2024-11-25T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2024/11/raw-development-guide/" type="text/html"/>
        <id>https://codedchords.dev/blog/2024/11/raw-development-guide/</id>
        
            <content type="html">&lt;h2 id=&quot;Introduction&quot;&gt;Introduction&lt;&#x2F;h2&gt;
&lt;p&gt;I’ve been using SILKYPIX to develop RAW images captured with my RICOH GR IIIx. However, I’ve recently started wondering: &lt;em&gt;Is it really worth continuing to use this software?&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;There are two main reasons for my hesitation:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;The processing takes a significant amount of time.&lt;&#x2F;li&gt;
&lt;li&gt;The preview feature is sluggish, and the software frequently freezes after extended use.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;With macOS now supporting RAW files natively, a variety of apps are available for editing these files. To explore my options, I wrote a Python-based image comparison tool and analyzed three images to see how they stack up:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Image 1&lt;&#x2F;strong&gt;: A JPEG file developed using the macOS version of SILKYPIX, without any adjustments.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Image 2&lt;&#x2F;strong&gt;: A JPEG file developed using Pixelmator Pro, also without adjustments. Pixelmator Pro takes advantage of macOS&#x27;s native RAW support, ensuring high compatibility and efficient processing of RAW files.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Image 3&lt;&#x2F;strong&gt;: A JPEG image saved directly from the GR IIIx at the time of capture, with the &quot;Negative Film&quot; preset applied via Image Control.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;私はRICOH GR IIIxで撮影したRAW画像の現像にSILKYPIXを使用してきました。しかし、最近こう考え始めています：このソフトウェアを使い続ける価値は本当にあるのだろうか？
ためらいの主な理由は2つあります。&lt;&#x2F;p&gt;
&lt;p&gt;処理に相当な時間がかかる。
プレビュー機能が遅く、長時間使用すると頻繁にフリーズする。&lt;&#x2F;p&gt;
&lt;p&gt;macOSが現在RAWファイルをネイティブにサポートするようになり、これらのファイルを編集するための様々なアプリが利用可能です。選択肢を探るために、Pythonベースの画像比較ツールを作成し、3つの画像を分析して比較しました。&lt;&#x2F;p&gt;
&lt;p&gt;画像1：macOS版のSILKYPIXを使用して現像したJPEGファイル（調整なし）。
画像2：Pixelmator Proを使用して現像したJPEGファイル（同じく調整なし）。Pixelmator ProはmacOSのネイティブRAWサポートを活用し、RAWファイルの高い互換性と効率的な処理を確保しています。
画像3：撮影時にGR IIIxから直接保存されたJPEG画像で、イメージコントロールを通じて「ネガティブフィルム」プリセットが適用されています。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;1._Analyzing_the_JPEG_Files_Using_Data&quot;&gt;1. Analyzing the JPEG Files Using Data&lt;&#x2F;h2&gt;
&lt;p&gt;The image I used for comparison was a park scene with autumn leaves illuminated by the setting sun.
Here are the results from my Python program:&lt;&#x2F;p&gt;
&lt;p&gt;比較に使用した画像は、夕日に照らされた秋の紅葉がある公園の風景です。
以下が私のPythonプログラムからの結果です。&lt;&#x2F;p&gt;
&lt;!-- textlint-disable --&gt;
&lt;img
  src=&quot;https:&amp;#x2F;&amp;#x2F;codedchords.dev&amp;#x2F;blog&amp;#x2F;2024&amp;#x2F;11&amp;#x2F;raw-development-guide&amp;#x2F;comparison-result.webp?h=c20ffddf97ed20b1dafa&quot;
  alt=&quot;Result of Comparison&quot; width=&quot;1500&quot; height=&quot;1000&quot; loading=&quot;lazy&quot;
&#x2F;&gt;&lt;!-- textlint-enable --&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;❯&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; python three-image-comparison.py&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;Image&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 1&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; Analysis:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;Size:&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; (4000,&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; 6000,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 3&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;Mean&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; Brightness:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 85.267&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;Standard&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; Deviation:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 72.58&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;Mean&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; Saturation:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 113.675&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;Contrast:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 255&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;File&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; Size&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;KB&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 19070.3955078125&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;Image&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 2&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; Analysis:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;Size:&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; (4000,&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; 6000,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 3&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;Mean&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; Brightness:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 66.147&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;Standard&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; Deviation:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 73.611&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;Mean&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; Saturation:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 135.691&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;Contrast:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 255&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;File&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; Size&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;KB&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 29992.3681640625&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;Image&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 3&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; Analysis:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;Size:&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; (4000,&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; 6000,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 3&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;Mean&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; Brightness:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 93.122&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;Standard&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; Deviation:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 74.255&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;Mean&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; Saturation:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 85.623&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;Contrast:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 255&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;File&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; Size&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;KB&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 13395.0634765625&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;Comparison&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; Results:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;SSIM&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; 1-2:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 0.68&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;SSIM&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; 1-3:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 0.847&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;SSIM&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; 2-3:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 0.737&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;Histogram&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; Correlation 1-2:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 0.3822719180861183&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;Histogram&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; Correlation 1-3:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 0.7985840630919663&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;Histogram&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; Correlation 2-3:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 0.13442670111231494&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;2._Insights_from_the_Image_Comparison&quot;&gt;2. Insights from the Image Comparison&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;2.1._Image_Comparison_Results&quot;&gt;2.1. Image Comparison Results&lt;&#x2F;h3&gt;
&lt;p&gt;The characteristics of each image based on the data are as follows:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;SILKYPIX Image&lt;&#x2F;strong&gt;
&lt;ul&gt;
&lt;li&gt;Moderate brightness with a calm tone.&lt;&#x2F;li&gt;
&lt;li&gt;Adequate saturation, achieving a balance of vibrancy and naturalness.&lt;&#x2F;li&gt;
&lt;li&gt;Stable brightness, resulting in a uniform finish.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Pixelmator Pro Image&lt;&#x2F;strong&gt;
&lt;ul&gt;
&lt;li&gt;The darkest output, emphasizing shadows.&lt;&#x2F;li&gt;
&lt;li&gt;The highest saturation, focusing on vibrancy.&lt;&#x2F;li&gt;
&lt;li&gt;Dynamic tonal changes, creating a dramatic impression.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;GR IIIx Jpeg Image (Negative Film Style)&lt;&#x2F;strong&gt;
&lt;ul&gt;
&lt;li&gt;The brightest output, with a light and soft tone.&lt;&#x2F;li&gt;
&lt;li&gt;The lowest saturation, offering a calm and natural color palette.&lt;&#x2F;li&gt;
&lt;li&gt;Moderate brightness variation, providing smooth and natural gradation.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;From the comparison results, the following observations can be made:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Based on &lt;strong&gt;SSIM (Structural Similarity Index)&lt;&#x2F;strong&gt;, SILKYPIX and Pixelmator Pro exhibit significantly different structures, with notable differences in brightness and saturation. The GR IIIx Jpeg is relatively similar to SILKYPIX but with more subdued saturation.&lt;&#x2F;li&gt;
&lt;li&gt;According to the &lt;strong&gt;Histogram Correlation&lt;&#x2F;strong&gt;, SILKYPIX and Pixelmator Pro show distinctly different color distributions. When compared to GR IIIx Jpeg, SILKYPIX has some similarity, while Pixelmator Pro displays significant differences.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;ータに基づく各画像の特徴は以下の通りです。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;SILKYPIX画像
&lt;ul&gt;
&lt;li&gt;穏やかなトーンの適度な明るさ。&lt;&#x2F;li&gt;
&lt;li&gt;適切な彩度で、鮮やかさと自然さのバランスを実現。&lt;&#x2F;li&gt;
&lt;li&gt;安定した明るさにより、均一な仕上がりになっている。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;Pixelmator Pro画像
&lt;ul&gt;
&lt;li&gt;最も暗い出力で、影を強調。&lt;&#x2F;li&gt;
&lt;li&gt;最も高い彩度で、鮮やかさに焦点。&lt;&#x2F;li&gt;
&lt;li&gt;ダイナミックな色調の変化により、ドラマチックな印象を作り出す。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;GR IIIx JPEG画像（ネガティブフィルムスタイル）
&lt;ul&gt;
&lt;li&gt;最も明るい出力で、明るく柔らかいトーン。&lt;&#x2F;li&gt;
&lt;li&gt;最も低い彩度で、落ち着いた自然な色調を提供。&lt;&#x2F;li&gt;
&lt;li&gt;適度な明るさのバリエーションにより、滑らかで自然なグラデーションを提供。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;比較結果から、以下の観察が可能です。&lt;&#x2F;p&gt;
&lt;p&gt;SSIM（構造的類似性指標）に基づくと、SILKYPIXとPixelmator Proは明るさと彩
度に顕著な違いがあり、構造が大きく異なります。GR IIIx JPEGはSILKYPIXと比較的
似ていますが、より控えめな彩度となっています。
ヒストグラム相関によると、SILKYPIXとPixelmator Proは明らかに異なる色分布を示しています。GR IIIx JPEGと比較すると、SILKYPIXにはある程度の類似性がありますが、Pixelmator Proは大きな違いを示しています。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;2.2._Evaluating_RAW_Development_Apps&quot;&gt;2.2. Evaluating RAW Development Apps&lt;&#x2F;h3&gt;
&lt;p&gt;Based on the analysis, here’s my evaluation of each tool:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;SILKYPIX&lt;&#x2F;strong&gt;&lt;br &#x2F;&gt;
SILKYPIX delivers vivid colors and a balanced brightness level, making it ideal for landscapes or scenes where vibrant colors are essential. Its versatility makes it suitable for various scenarios.SILKYPIXは鮮やかな色とバランスの取れた明るさのレベルを提供し、鮮やかな色が重要な風景やシーンに理想的。その多様性により、様々なシナリオに適している。&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Pixelmator Pro&lt;&#x2F;strong&gt;&lt;br &#x2F;&gt;
With its darker tones and shadow emphasis, Pixelmator Pro works well for dramatic compositions or print projects. However, additional adjustments might be required for darker areas.より暗いトーンと影の強調により、Pixelmator Proはドラマチックな構図や印刷プロジェクトに適している。ただし、暗い部分には追加の調整が必要な場合がある。&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;GR IIIx JPEG (Negative Film Preset)&lt;&#x2F;strong&gt;&lt;br &#x2F;&gt;
The GR IIIx JPEG provides a bright, soft tone with natural colors, making
it great for everyday photography and relaxed scenes.GR IIIx JPEGは明るく柔
らかいトーンと自然な色を提供し、日常の写真や落ち着いたシーンに最適。&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;3._Final_Thoughts&quot;&gt;3. Final Thoughts&lt;&#x2F;h2&gt;
&lt;p&gt;From this comparison, SILKYPIX proves to be a reliable tool, and the numerical data supports its strengths. Surprisingly, I found myself drawn to the GR IIIx JPEG with the Negative Film preset.&lt;&#x2F;p&gt;
&lt;p&gt;A practical workflow could be to shoot in RAW + JPEG mode, using the JPEGs directly for most situations and turning to SILKYPIX for advanced adjustments when needed.&lt;&#x2F;p&gt;
&lt;p&gt;この比較から、SILKYPIXは信頼性の高いツールであり、数値データがその強みを裏付けています。驚いたことに、ネガティブフィルムプリセットを適用したGR IIIx JPEGに魅力を感じました。
実用的なワークフローとしては、RAW + JPEGモードで撮影し、
ほとんどの状況では直接JPEGを使用し、必要に応じてSILKYPIXを使用して調整することが考えられます。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;Appendix._Python_Program_for_Image_Analysis&quot;&gt;Appendix. Python Program for Image Analysis&lt;&#x2F;h2&gt;
&lt;p&gt;Here is the Python program I used for this analysis. It’s a quick and simple script, so it includes hard-coded file names for convenience. Feel free to adapt it to your needs.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;python&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;from&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; PIL&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; import&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; Image&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;from&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; skimage&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;metrics&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; import&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; structural_similarity&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; as&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; ssim&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-python&quot;&gt;def&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; compare_three_images&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt;image1_path&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt; image2_path&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt; image3_path&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt; output_path&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language z-python&quot;&gt;None&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;):&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;    &amp;quot;&amp;quot;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;    Compare three images and analyze them using various metrics&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;    Parameters:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;    image1_path (str): Path to first image&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;    image2_path (str): Path to second image&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;    image3_path (str): Path to third image&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;    output_path (str): Path to save comparison results (optional)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;    Returns:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;    dict: Comparison metrics&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;    &amp;quot;&amp;quot;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;    # Load images&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    img1&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; cv2&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;imread&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;image1_path&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt; cv2&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;IMREAD_UNCHANGED&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    img2&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; cv2&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;imread&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;image2_path&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt; cv2&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;IMREAD_UNCHANGED&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    img3&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; cv2&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;imread&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;image3_path&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt; cv2&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;IMREAD_UNCHANGED&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-control z-flow z-python&quot;&gt;    if&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; img1&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-logical z-python&quot;&gt; is&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language z-python&quot;&gt; None&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-logical z-python&quot;&gt; or&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; img2&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-logical z-python&quot;&gt; is&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language z-python&quot;&gt; None&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-logical z-python&quot;&gt; or&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; img3&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-logical z-python&quot;&gt; is&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language z-python&quot;&gt; None&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-control z-flow z-python&quot;&gt;        raise&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-exception z-python&quot;&gt; ValueError&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;Failed to load one or more images&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;    # Normalize to 8-bit if necessary for visualization&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-python&quot;&gt;    def&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; normalize_to_8bit&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt;img&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;):&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-control z-flow z-python&quot;&gt;        if&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; img&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;dtype&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; !=&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; np&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;uint8&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-control z-flow z-python&quot;&gt;            return&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; cv2&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;normalize&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;img&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language z-python&quot;&gt; None&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 0&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 255&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt; cv2&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;NORM_MINMAX&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt; dtype&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;cv2&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;CV_8U&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-control z-flow z-python&quot;&gt;        return&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; img&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    img1_8bit&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt; normalize_to_8bit&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;img1&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    img2_8bit&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt; normalize_to_8bit&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;img2&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    img3_8bit&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt; normalize_to_8bit&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;img3&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;    # Convert to grayscale for SSIM&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    gray1&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; cv2&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;cvtColor&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;img1_8bit&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt; cv2&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;COLOR_BGR2GRAY&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    gray2&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; cv2&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;cvtColor&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;img2_8bit&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt; cv2&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;COLOR_BGR2GRAY&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    gray3&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; cv2&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;cvtColor&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;img3_8bit&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt; cv2&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;COLOR_BGR2GRAY&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;    # Calculate SSIM between each pair&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    ssim_1_2&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt; ssim&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;gray1&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt; gray2&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    ssim_1_3&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt; ssim&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;gray1&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt; gray3&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    ssim_2_3&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt; ssim&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;gray2&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt; gray3&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;    # Compare histograms between each pair&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-python&quot;&gt;    def&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; calculate_hist_correlation&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt;img1&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt; img2&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;):&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;        hist1&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; cv2&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;calcHist&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;([&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;img1&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;], [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;0&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;],&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language z-python&quot;&gt; None&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;, [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;256&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;], [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;0&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 256&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;])&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;        hist2&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; cv2&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;calcHist&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;([&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;img2&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;], [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;0&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;],&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language z-python&quot;&gt; None&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;, [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;256&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;], [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;0&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 256&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;])&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-control z-flow z-python&quot;&gt;        return&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; cv2&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;compareHist&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;hist1&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt; hist2&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt; cv2&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;HISTCMP_CORREL&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    hist_corr_1_2&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt; calculate_hist_correlation&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;img1_8bit&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt; img2_8bit&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    hist_corr_1_3&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt; calculate_hist_correlation&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;img1_8bit&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt; img3_8bit&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    hist_corr_2_3&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt; calculate_hist_correlation&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;img2_8bit&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt; img3_8bit&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;    # Visualization&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    plt&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;figure&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt;figsize&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;15&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 10&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;))&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;    # Images&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    plt&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;subplot&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;231&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    plt&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;imshow&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;cv2&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;cvtColor&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;img1_8bit&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt; cv2&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;COLOR_BGR2RGB&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;))&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    plt&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;title&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;Image 1&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    plt&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;axis&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;off&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    plt&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;subplot&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;232&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    plt&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;imshow&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;cv2&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;cvtColor&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;img2_8bit&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt; cv2&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;COLOR_BGR2RGB&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;))&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    plt&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;title&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;Image 2&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    plt&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;axis&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;off&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    plt&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;subplot&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;233&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    plt&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;imshow&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;cv2&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;cvtColor&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;img3_8bit&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt; cv2&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;COLOR_BGR2RGB&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;))&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    plt&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;title&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;Image 3&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    plt&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;axis&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;off&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;    # Histograms&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    plt&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;subplot&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;234&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    plt&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;hist&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;img1_8bit&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;ravel&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(),&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 256&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;, [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;0&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 256&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;])&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    plt&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;title&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;Histogram - Image 1&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    plt&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;subplot&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;235&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    plt&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;hist&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;img2_8bit&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;ravel&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(),&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 256&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;, [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;0&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 256&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;])&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    plt&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;title&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;Histogram - Image 2&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    plt&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;subplot&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;236&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    plt&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;hist&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;img3_8bit&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;ravel&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(),&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 256&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;, [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;0&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 256&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;])&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    plt&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;title&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;Histogram - Image 3&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-control z-flow z-python&quot;&gt;    if&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; output_path&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;        plt&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;savefig&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;output_path&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    plt&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;close&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-control z-flow z-python&quot;&gt;    return&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;        &amp;quot;SSIM 1-2&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; ssim_1_2&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;        &amp;quot;SSIM 1-3&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; ssim_1_3&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;        &amp;quot;SSIM 2-3&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; ssim_2_3&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;        &amp;quot;Histogram Correlation 1-2&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; hist_corr_1_2&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;        &amp;quot;Histogram Correlation 1-3&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; hist_corr_1_3&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;        &amp;quot;Histogram Correlation 2-3&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; hist_corr_2_3&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;        &amp;quot;Size&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; img1&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;shape&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;        &amp;quot;Bit Depth 1&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-python&quot;&gt; str&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;img1&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;dtype&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;        &amp;quot;Bit Depth 2&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-python&quot;&gt; str&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;img2&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;dtype&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;        &amp;quot;Bit Depth 3&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-python&quot;&gt; str&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;img3&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;dtype&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-python&quot;&gt;def&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; analyze_image&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt;image_path&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;):&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;    &amp;quot;&amp;quot;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;    Analyze one image&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;    Parameters:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;    image_path (str): path to the image&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;    Returns:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;    dict: results of analysis&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;    &amp;quot;&amp;quot;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    img&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; cv2&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;imread&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;image_path&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    hsv&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; cv2&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;cvtColor&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;img&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt; cv2&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;COLOR_BGR2HSV&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-control z-flow z-python&quot;&gt;    return&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;        &amp;quot;Size&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; img&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;shape&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;        &amp;quot;Mean Brightness&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; np&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;mean&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;img&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;        &amp;quot;Standard Deviation&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; np&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;std&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;img&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;        &amp;quot;Mean Saturation&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; np&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;mean&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-indexed-name z-python&quot;&gt;hsv&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[:, :,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 1&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;        &amp;quot;Contrast&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; np&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;max&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;img&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; -&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; np&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;min&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;img&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;        &amp;quot;File Size(KB)&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; os&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;path&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;getsize&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;image_path&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; &#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 1024&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;  # KB単位&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-python&quot;&gt;def&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; format_results&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt;results_dict&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;):&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;    &amp;quot;&amp;quot;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;    Format the results dictionary for better readability&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;    &amp;quot;&amp;quot;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    formatted&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; {}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-control z-flow z-python&quot;&gt;    for&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; key&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; value&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-control z-flow z-python&quot;&gt; in&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; results_dict&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;items&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;():&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-control z-flow z-python&quot;&gt;        if&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-builtin z-python&quot;&gt; isinstance&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;value&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;, (&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;np&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;float64&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt; np&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;float32&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)):&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-meta z-indexed-name z-python&quot;&gt;            formatted&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-item-access z-python&quot;&gt;key&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-python&quot;&gt; float&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-builtin z-python&quot;&gt;round&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;value&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 3&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;))&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-control z-flow z-python&quot;&gt;        elif&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-builtin z-python&quot;&gt; isinstance&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;value&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt; np&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;uint8&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;):&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-meta z-indexed-name z-python&quot;&gt;            formatted&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-item-access z-python&quot;&gt;key&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type z-python&quot;&gt; int&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;value&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-control z-flow z-python&quot;&gt;        else&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-meta z-indexed-name z-python&quot;&gt;            formatted&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-item-access z-python&quot;&gt;key&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; value&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-control z-flow z-python&quot;&gt;    return&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; formatted&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-control z-flow z-python&quot;&gt;if&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-variable z-magic z-python&quot;&gt; __name__&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; ==&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;__main__&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;    # Compare three images&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    results&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt; compare_three_images&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;        &amp;quot;image1.jpg&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;image2.jpg&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;image3.jpg&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;comparison_result.png&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    )&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;    # Analyze each image&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    images&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;image1.jpg&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;image2.jpg&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;image3.jpg&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-control z-flow z-python&quot;&gt;    for&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; i&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; image_path&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-control z-flow z-python&quot;&gt; in&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-builtin z-python&quot;&gt; enumerate&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;images&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 1&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;):&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;        analysis&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt; analyze_image&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;image_path&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-function z-builtin z-python&quot;&gt;        print&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-string z-python&quot;&gt;f&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;Image &lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-format z-placeholder z-other z-python&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;i&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-format z-placeholder z-other z-python&quot;&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; Analysis:&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-control z-flow z-python&quot;&gt;        for&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; key&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; value&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-control z-flow z-python&quot;&gt; in&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt; format_results&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;analysis&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;).&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;items&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;():&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-function z-builtin z-python&quot;&gt;            print&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-string z-python&quot;&gt;f&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-format z-placeholder z-other z-python&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;key&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-format z-placeholder z-other z-python&quot;&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;: &lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-format z-placeholder z-other z-python&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;value&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-format z-placeholder z-other z-python&quot;&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-function z-builtin z-python&quot;&gt;    print&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt;Comparison Results:&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-control z-flow z-python&quot;&gt;    for&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; key&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; value&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-control z-flow z-python&quot;&gt; in&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt; format_results&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;results&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;).&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;items&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;():&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-function z-builtin z-python&quot;&gt;        print&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-string z-python&quot;&gt;f&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-format z-placeholder z-other z-python&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;key&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-format z-placeholder z-other z-python&quot;&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;: &lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-format z-placeholder z-other z-python&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;value&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-format z-placeholder z-other z-python&quot;&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;</content>
        <summary type="html">RAW現像について、SILKYPIX, Pixelmator Pro, GR IIIx JPEG の比較を行っています。</summary>
        </entry><entry xml:lang="en">
        <title>『プログラミング言語AWK 第2版』</title>
        <published>2024-11-15T00:00:00+00:00</published>
        <updated>2024-11-15T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2024/11/awk/" type="text/html"/>
        <id>https://codedchords.dev/blog/2024/11/awk/</id>
        
            <content type="html">&lt;p&gt;『&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;amzn.to&#x2F;43TVF97&quot;&gt;プログラミング言語AWK 第2版&lt;&#x2F;a&gt;』が出ていました。
35年ぶりの刷新だそうです。&lt;&#x2F;p&gt;
&lt;p&gt;懐かしくて、購入してみました。ほんとに懐かしい。&lt;&#x2F;p&gt;
&lt;div class=&quot;booklink-box&quot; style=&quot;text-align:left;padding-bottom:20px;font-size:small;zoom: 1;overflow: hidden;&quot;&gt;&lt;div class=&quot;booklink-image&quot; style=&quot;float:left;margin:0 15px 10px 0;&quot;&gt;&lt;a href=&quot;https:&#x2F;&#x2F;hb.afl.rakuten.co.jp&#x2F;hgc&#x2F;1300574f.7d238558.13005750.4bcd8088&#x2F;yomereba_main_202601292059468673?pc=http%3A%2F%2Fbooks.rakuten.co.jp%2Frb%2F17829911%2F%3Frafcid%3Dwsc_b_bs_1051722217600006323%3Fscid%3Daf_ich_link_urltxt%26m%3Dhttp%3A%2F%2Fm.rakuten.co.jp%2Fev%2Fbook%2F&quot; target=&quot;_blank&quot; &gt;&lt;img src=&quot;https:&#x2F;&#x2F;thumbnail.image.rakuten.co.jp&#x2F;@0_mall&#x2F;book&#x2F;cabinet&#x2F;0706&#x2F;9784814400706_1_3.jpg?_ex=200x200&quot; style=&quot;border: none;&quot; &#x2F;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;div&gt;&lt;div class=&quot;booklink-info&quot; style=&quot;line-height:120%;zoom: 1;overflow: hidden;&quot;&gt;&lt;div class=&quot;booklink-name&quot; style=&quot;margin-bottom:10px;line-height:120%&quot;&gt;&lt;a href=&quot;https:&#x2F;&#x2F;hb.afl.rakuten.co.jp&#x2F;hgc&#x2F;1300574f.7d238558.13005750.4bcd8088&#x2F;yomereba_main_202601292059468673?pc=http%3A%2F%2Fbooks.rakuten.co.jp%2Frb%2F17829911%2F%3Frafcid%3Dwsc_b_bs_1051722217600006323%3Fscid%3Daf_ich_link_urltxt%26m%3Dhttp%3A%2F%2Fm.rakuten.co.jp%2Fev%2Fbook%2F&quot; target=&quot;_blank&quot; &gt;プログラミング言語AWK（第2版）&lt;&#x2F;a&gt;&lt;div class=&quot;booklink-powered-date&quot; style=&quot;font-size:8pt;margin-top:5px;font-family:verdana;line-height:120%&quot;&gt;posted with &lt;a href=&quot;https:&#x2F;&#x2F;yomereba.com&quot; rel=&quot;nofollow&quot; target=&quot;_blank&quot;&gt;ヨメレバ&lt;&#x2F;a&gt;&lt;&#x2F;div&gt;&lt;&#x2F;div&gt;&lt;div class=&quot;booklink-detail&quot; style=&quot;margin-bottom:5px;&quot;&gt;Alfred V. Aho&#x2F;Brian W. Kernighan&#x2F;Peter J. Weinberger&#x2F;千住 治郎 オライリー・ジャパン 2024年05月16日頃    &lt;&#x2F;div&gt;&lt;div class=&quot;booklink-link2&quot; style=&quot;margin-top:10px;&quot;&gt;&lt;div class=&quot;shoplinkrakuten&quot; style=&quot;display:inline;margin-right:5px&quot;&gt;&lt;a href=&quot;https:&#x2F;&#x2F;hb.afl.rakuten.co.jp&#x2F;hgc&#x2F;1300574f.7d238558.13005750.4bcd8088&#x2F;yomereba_main_202601292059468673?pc=http%3A%2F%2Fbooks.rakuten.co.jp%2Frb%2F17829911%2F%3Frafcid%3Dwsc_b_bs_1051722217600006323%3Fscid%3Daf_ich_link_urltxt%26m%3Dhttp%3A%2F%2Fm.rakuten.co.jp%2Fev%2Fbook%2F&quot; target=&quot;_blank&quot; &gt;楽天ブックス&lt;&#x2F;a&gt;&lt;&#x2F;div&gt;&lt;div class=&quot;shoplinkamazon&quot; style=&quot;display:inline;margin-right:5px&quot;&gt;&lt;a href=&quot;https:&#x2F;&#x2F;www.amazon.co.jp&#x2F;exec&#x2F;obidos&#x2F;asin&#x2F;4814400705&#x2F;yostosweb-22&#x2F;&quot; target=&quot;_blank&quot; &gt;Amazon&lt;&#x2F;a&gt;&lt;&#x2F;div&gt;&lt;div class=&quot;shoplinkkindle&quot; style=&quot;display:inline;margin-right:5px&quot;&gt;&lt;a href=&quot;https:&#x2F;&#x2F;www.amazon.co.jp&#x2F;gp&#x2F;search?keywords=%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0%E8%A8%80%E8%AA%9EAWK%EF%BC%88%E7%AC%AC2%E7%89%88%EF%BC%89&amp;__mk_ja_JP=%83J%83%5E%83J%83i&amp;url=node%3D2275256051&amp;tag=yostosweb-22&quot; target=&quot;_blank&quot; &gt;Kindle&lt;&#x2F;a&gt;&lt;&#x2F;div&gt;                                           &lt;&#x2F;div&gt;&lt;&#x2F;div&gt;&lt;div class=&quot;booklink-footer&quot; style=&quot;clear: left&quot;&gt;&lt;&#x2F;div&gt;&lt;&#x2F;div&gt;
</content>
        <summary type="html">35年ぶりの刷新だそうです。つい買ってしまいました。</summary>
        </entry><entry xml:lang="en">
        <title>Goodbye Bartender!</title>
        <published>2024-11-12T00:00:00+00:00</published>
        <updated>2024-11-12T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2024/11/goodbye-bartender/" type="text/html"/>
        <id>https://codedchords.dev/blog/2024/11/goodbye-bartender/</id>
        
            <content type="html">&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.macbartender.com&#x2F;&quot;&gt;Bartender&lt;&#x2F;a&gt; was menu bar wizard I&#x27;d been geeking out over. Turned out Ben Surtees had sold it to some shadowy outfit called Applause in March 2024. Reddit blew up with users freaking out.
Today, I&#x27;ve now ditched Bartender for Ice,too.&lt;&#x2F;p&gt;
&lt;p&gt;Keep it FOSS, keep it safe, am I right?&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.macbartender.com&#x2F;&quot;&gt;バーテンダー&lt;&#x2F;a&gt;はメニューバーの魔術師で、私は熱中していました。ベン・サーティーズが2024年3月にApplauseという正体不明の会社に売却していたことが判明しました。Redditではユーザーたちが大騒ぎしていました。
今日、私もバーテンダーを捨ててIceに乗り換えました。&lt;&#x2F;p&gt;
&lt;p&gt;オープンソースを守れば安全、そうでしょ？&lt;&#x2F;p&gt;
</content>
        <summary type="html">Macのメニュー管理アプリのBartenderが結構まずいことになっていました。</summary>
        </entry><entry xml:lang="en">
        <title>S3静的ウェブサイトのインデックス解決をCloudFront Functionsで修正</title>
        <published>2024-11-05T00:00:00+00:00</published>
        <updated>2024-11-05T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2024/11/fixing-s3-cloudfront-index-resolution/" type="text/html"/>
        <id>https://codedchords.dev/blog/2024/11/fixing-s3-cloudfront-index-resolution/</id>
        
            <content type="html">&lt;p&gt;メインブログをCloudflareからAWS S3へと移行した際、
S3のBlock pubic accessをオフ、Static website hostingをオンにしていたので、
CloudFrontがS3のREST APIエンドポイントを使用するよう修正しました。&lt;&#x2F;p&gt;
&lt;p&gt;この場合CloudFrontはサブディレクトリのindex.htmlファイルを自動的に解決できないので、以下のURLのパスを適切に変換するCloudFront Functionsを追加しました。&lt;&#x2F;p&gt;
&lt;p&gt;ありがちな事ですね。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;function&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; handler&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt;event&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;  var&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt; request&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; event&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-property z-js&quot;&gt;request&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;  var&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt; uri&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; request&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-property z-js&quot;&gt;uri&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;  &#x2F;&#x2F; URIが&#x2F;で終わる場合、index.htmlを追加&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;  if&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; (uri&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;endsWith&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;&#x2F;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;))&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    request&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-property z-js&quot;&gt;uri&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; +=&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;index.html&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;  }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;  &#x2F;&#x2F; 拡張子がない場合もindex.htmlを追加&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;  else if&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; (&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;!&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;uri&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;includes&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;quot;.&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;))&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;    request&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-property z-js&quot;&gt;uri&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; +=&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt; &amp;quot;&#x2F;index.html&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;  }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;  return&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt; request&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;</content>
        <summary type="html">CloudFlareからブログを移行した際に、パスの指定で問題がでていたので修正しました。</summary>
        </entry><entry xml:lang="en">
        <title>Intel、大丈夫か？</title>
        <published>2024-11-01T00:00:00+00:00</published>
        <updated>2024-11-01T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2024/11/intel/" type="text/html"/>
        <id>https://codedchords.dev/blog/2024/11/intel/</id>
        
            <content type="html">&lt;blockquote cite=&quot;https:&#x2F;&#x2F;www3.nhk.or.jp&#x2F;news&#x2F;html&#x2F;20241101&#x2F;k10014625881000.html&quot;&gt;
  売り上げは前の年の同じ時期より6％減少して132億8400万ドル、日本円でおよそ2
  兆100億円、最終的な損益は166億3900万ドルの赤字、日本円でおよそ2兆5200億円
  の赤字でした。最終赤字となるのは3四半期連続です。
  &lt;cite&gt;
    &lt;a href=&quot;https:&#x2F;&#x2F;www3.nhk.or.jp&#x2F;news&#x2F;html&#x2F;20241101&#x2F;k10014625881000.html&quot;&gt;
      米 インテル 約2兆5000億円の最終赤字 半導体めぐる競争で | NHK
    &lt;&#x2F;a&gt;
  &lt;&#x2F;cite&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;今回は減損処理による特別損失のようですが、近年はCPU市場ではAMDの台頭、製造プロセスではTSMCに対抗できず、AI向けチップは完全に出遅れています。&lt;&#x2F;p&gt;
&lt;p&gt;以下はPerplexityで作成したPC向けCPUのシェアです。AppleのIntel離反があるにしてもAMDにかなりやられているのがよくわかります(2021年以前についてはデータがないので、断片情報からの類推が含まれています。)&lt;&#x2F;p&gt;
&lt;!-- textlint-disable --&gt;
&lt;img
  src=&quot;https:&amp;#x2F;&amp;#x2F;codedchords.dev&amp;#x2F;blog&amp;#x2F;2024&amp;#x2F;11&amp;#x2F;intel&amp;#x2F;intel-vs-amd.webp?h=8ef3542f94da8cb0d01e&quot;
  alt=&quot;Intel vs AMD&quot; width=&quot;1189&quot; height=&quot;590&quot; loading=&quot;lazy&quot;
&#x2F;&gt;&lt;!-- textlint-enable --&gt;
</content>
        <summary type="html">Intelは今期も赤字で、しかも2兆円を上回る赤字だったそうです。</summary>
        </entry><entry xml:lang="en">
        <title>M4 Macbook has been announced</title>
        <published>2024-10-31T00:00:00+00:00</published>
        <updated>2024-10-31T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2024/10/m4-mac/" type="text/html"/>
        <id>https://codedchords.dev/blog/2024/10/m4-mac/</id>
        
            <content type="html">&lt;p&gt;I&#x27;m currently using a MacBook Pro with M3 Max, so I&#x27;ve made a comparison between the M3 Max and M4 Max. I think I&#x27;ll continue using my current MacBook Pro for a while longer rather than upgrading.&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Chip Model&lt;&#x2F;th&gt;&lt;th&gt;CPU Core Count&lt;&#x2F;th&gt;&lt;th&gt;GPU Core Count&lt;&#x2F;th&gt;&lt;th&gt;Benchmark Scores&lt;&#x2F;th&gt;&lt;th&gt;Transistor Count (Billions)&lt;&#x2F;th&gt;&lt;th&gt;Memory Bandwidth (GB&#x2F;s)&lt;&#x2F;th&gt;&lt;th&gt;Release Date&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;M3 Max&lt;&#x2F;td&gt;&lt;td&gt;12&#x2F;4&lt;&#x2F;td&gt;&lt;td&gt;40&lt;&#x2F;td&gt;&lt;td&gt;Single: 2971, Multi: 20785&lt;&#x2F;td&gt;&lt;td&gt;92&lt;&#x2F;td&gt;&lt;td&gt;400&lt;&#x2F;td&gt;&lt;td&gt;2023-10-30&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;M4&lt;&#x2F;td&gt;&lt;td&gt;4&#x2F;6&lt;&#x2F;td&gt;&lt;td&gt;10&lt;&#x2F;td&gt;&lt;td&gt;—&lt;&#x2F;td&gt;&lt;td&gt;28&lt;&#x2F;td&gt;&lt;td&gt;120&lt;&#x2F;td&gt;&lt;td&gt;2024-05-15&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;M4 Pro&lt;&#x2F;td&gt;&lt;td&gt;10&#x2F;4&lt;&#x2F;td&gt;&lt;td&gt;20&lt;&#x2F;td&gt;&lt;td&gt;—&lt;&#x2F;td&gt;&lt;td&gt;Not announced&lt;&#x2F;td&gt;&lt;td&gt;120&lt;&#x2F;td&gt;&lt;td&gt;2024-10-29&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;M4 Max&lt;&#x2F;td&gt;&lt;td&gt;12&#x2F;4&lt;&#x2F;td&gt;&lt;td&gt;40&lt;&#x2F;td&gt;&lt;td&gt;—&lt;&#x2F;td&gt;&lt;td&gt;Not announced&lt;&#x2F;td&gt;&lt;td&gt;546&lt;&#x2F;td&gt;&lt;td&gt;2024-05-15&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
</content>
        <summary type="html">The MacBook Pro featuring the M4 chip has been announced.</summary>
        </entry><entry xml:lang="en">
        <title>The Ultimate Showdown: A Deep Dive into Modern Messaging Apps</title>
        <published>2024-10-23T00:00:00+00:00</published>
        <updated>2026-07-01T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2024/10/modern-messaging-apps/" type="text/html"/>
        <id>https://codedchords.dev/blog/2024/10/modern-messaging-apps/</id>
        
            <content type="html">&lt;p&gt;市川強盗傷害事件で犯人たちが「秘匿性が高い通信アプリを使用」とアプリ名を伏せて報道されています。
どうやら&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;signal.org&#x2F;ja&#x2F;&quot;&gt;Signal&lt;&#x2F;a&gt;を使っていたようです。こうなるとバカなメディアや視聴者が「邪悪なアプリ」と騒ぎ出しそうですね。&lt;&#x2F;p&gt;
&lt;p&gt;プライバシー&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-1-1&quot;&gt;&lt;a href=&quot;#fn-1&quot;&gt;1&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;
を考慮すると当然の選択ですね。公安や自衛隊でもSignalを奨励しているようです。
不完全な暗号化やメタデータ収集するLINEとかいうアプリを使っている能天気なメディアや視聴者より、
犯人たちのほうがよほど高いリテラシーを持っていたということでしょう。&lt;&#x2F;p&gt;
&lt;p&gt;気になったので、主要なメッセージングアプリについての比較表を作ってみました。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;メッセージングアプリの総合比較表&quot;&gt;メッセージングアプリの総合比較表&lt;&#x2F;h2&gt;
&lt;p&gt;以下は主なメッセージングアプリのついての比較をまとめた表です。&lt;&#x2F;p&gt;
&lt;p&gt;犯人たちが&lt;strong&gt;Signal&lt;&#x2F;strong&gt;を使ったのも納得です。日本ではユーザーが少ないので利用シーンは限られますが。
次点で &lt;strong&gt;Threema&lt;&#x2F;strong&gt; ですね。私は家族で使用しています。&lt;&#x2F;p&gt;
&lt;p&gt;iPhoneユーザーであれば &lt;strong&gt;iMessage&lt;&#x2F;strong&gt; は無難でしょう。完全にE2Eで暗号化されており、メタ情報の収集はされているようですが、Appleなので多少はマシだと思います。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Telegram&lt;&#x2F;strong&gt; はテロリストが使用しているイメージはありますが、意外に脆弱です。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;LINE&lt;&#x2F;strong&gt;については、日本でもユーザーが多いので補足を入れています。
やはりLINEは暗号化も不完全でデフォルトの状態ですし、メタ情報&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-1-2&quot;&gt;&lt;a href=&quot;#fn-1&quot;&gt;1&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;をかなり収集してお
り、おまけに透明性の観点でもいろいろと問題&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-2-1&quot;&gt;&lt;a href=&quot;#fn-2&quot;&gt;2&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;がありました。&lt;&#x2F;p&gt;
&lt;p&gt;こう並べてみると、&lt;strong&gt;LINE&lt;&#x2F;strong&gt; を選択する意味が私にはわかりません。&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;機能&#x2F;特徴&lt;&#x2F;th&gt;&lt;th&gt;LINE&lt;&#x2F;th&gt;&lt;th&gt;Signal&lt;&#x2F;th&gt;&lt;th&gt;Threema&lt;&#x2F;th&gt;&lt;th&gt;WhatsApp&lt;&#x2F;th&gt;&lt;th&gt;iMessage&lt;&#x2F;th&gt;&lt;th&gt;Telegram&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;E2E暗号化&lt;&#x2F;td&gt;&lt;td&gt;部分対応[暗号化WP] ※1&lt;&#x2F;td&gt;&lt;td&gt;完全対応&lt;&#x2F;td&gt;&lt;td&gt;完全対応&lt;&#x2F;td&gt;&lt;td&gt;完全対応&lt;&#x2F;td&gt;&lt;td&gt;完全対応&lt;&#x2F;td&gt;&lt;td&gt;Secret Chatのみ&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;グループチャット暗号化&lt;&#x2F;td&gt;&lt;td&gt;50人以下のみ[暗号化WP]&lt;&#x2F;td&gt;&lt;td&gt;完全対応&lt;&#x2F;td&gt;&lt;td&gt;完全対応&lt;&#x2F;td&gt;&lt;td&gt;完全対応&lt;&#x2F;td&gt;&lt;td&gt;完全対応&lt;&#x2F;td&gt;&lt;td&gt;Secret Chatのみ&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;メタデータ収集&lt;&#x2F;td&gt;&lt;td&gt;多い[PP] ※2&lt;&#x2F;td&gt;&lt;td&gt;最小限&lt;&#x2F;td&gt;&lt;td&gt;最小限&lt;&#x2F;td&gt;&lt;td&gt;多い&lt;&#x2F;td&gt;&lt;td&gt;中程度&lt;&#x2F;td&gt;&lt;td&gt;中程度&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;データストレージ&lt;&#x2F;td&gt;&lt;td&gt;サーバー保存[暗号化WP,PP] ※3&lt;&#x2F;td&gt;&lt;td&gt;端末のみ&lt;&#x2F;td&gt;&lt;td&gt;端末のみ&lt;&#x2F;td&gt;&lt;td&gt;クラウド可能&lt;&#x2F;td&gt;&lt;td&gt;iCloud連携時保存&lt;&#x2F;td&gt;&lt;td&gt;サーバー保存&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;電話番号必須&lt;&#x2F;td&gt;&lt;td&gt;はい[PP]&lt;&#x2F;td&gt;&lt;td&gt;はい&lt;&#x2F;td&gt;&lt;td&gt;いいえ&lt;&#x2F;td&gt;&lt;td&gt;はい&lt;&#x2F;td&gt;&lt;td&gt;いいえ&lt;&#x2F;td&gt;&lt;td&gt;はい&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;自動消去機能&lt;&#x2F;td&gt;&lt;td&gt;24時間のみ[PP]&lt;&#x2F;td&gt;&lt;td&gt;1秒～4週間&lt;&#x2F;td&gt;&lt;td&gt;カスタム設定可&lt;&#x2F;td&gt;&lt;td&gt;24時間～90日&lt;&#x2F;td&gt;&lt;td&gt;2分～4週間&lt;&#x2F;td&gt;&lt;td&gt;1秒～1週間&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;法執行機関への情報開示&lt;&#x2F;td&gt;&lt;td&gt;多い[TR] ※4&lt;&#x2F;td&gt;&lt;td&gt;最小限&lt;&#x2F;td&gt;&lt;td&gt;最小限&lt;&#x2F;td&gt;&lt;td&gt;多い&lt;&#x2F;td&gt;&lt;td&gt;一部可能&lt;&#x2F;td&gt;&lt;td&gt;最小限&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;追加機能&lt;&#x2F;td&gt;&lt;td&gt;スタンプ&#x2F;ゲーム&#x2F;決済&#x2F;音声・ビデオ通話[PP]&lt;&#x2F;td&gt;&lt;td&gt;スタンプ&#x2F;音声・ビデオ通話&lt;&#x2F;td&gt;&lt;td&gt;投票&#x2F;音声・ビデオ通話&lt;&#x2F;td&gt;&lt;td&gt;ステータス&#x2F;音声・ビデオ通話&#x2F;決済&lt;&#x2F;td&gt;&lt;td&gt;Apple統合&#x2F;音声・ビデオ通話&lt;&#x2F;td&gt;&lt;td&gt;Bot&#x2F;チャンネル&#x2F;音声・ビデオ通話&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;オープンソース&lt;&#x2F;td&gt;&lt;td&gt;一部のみ[暗号化WP]&lt;&#x2F;td&gt;&lt;td&gt;完全対応&lt;&#x2F;td&gt;&lt;td&gt;一部のみ&lt;&#x2F;td&gt;&lt;td&gt;なし&lt;&#x2F;td&gt;&lt;td&gt;なし&lt;&#x2F;td&gt;&lt;td&gt;クライアントのみ&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;ul&gt;
&lt;li&gt;※1: LINEのE2E暗号化（Letter Sealing）対応範囲(doc.1) &lt;ins&gt;（2026年7月追記: 2024年後半にLetter Sealingの保護対象が拡大されました。出典: &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.lycorp.co.jp&#x2F;ja&#x2F;privacy-security&#x2F;security&#x2F;transparency&#x2F;encryption-report&#x2F;2025&#x2F;&quot;&gt;LINE暗号化状況レポート（2025年）&lt;&#x2F;a&gt;）&lt;&#x2F;ins&gt;
&lt;ul&gt;
&lt;li&gt;対応: テキスト・位置情報（1対1と50人以下グループ）、1対1音声・ビデオ通話&lt;ins&gt;、画像・動画・音声メッセージ・ファイル添付（2024年後半に対応。1対1と50人以下グループ）&lt;&#x2F;ins&gt;&lt;&#x2F;li&gt;
&lt;li&gt;非対応: &lt;del&gt;画像、動画、ファイル添付、&lt;&#x2F;del&gt;50人以上グループ、グループ通話、LINEミーティング&lt;ins&gt;、アルバム、ノート&lt;&#x2F;ins&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;※2: LINEのメタデータ収集内容(doc.2)
&lt;ul&gt;
&lt;li&gt;アカウント情報（電話番号、メールアドレス）&lt;&#x2F;li&gt;
&lt;li&gt;デバイス情報（使用OS、言語設定）&lt;&#x2F;li&gt;
&lt;li&gt;アプリの使用頻度情報&lt;&#x2F;li&gt;
&lt;li&gt;位置情報（設定による）&lt;&#x2F;li&gt;
&lt;li&gt;友達関係の情報&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;※3: LINEのデータストレージ(doc.1,doc.2)
&lt;ul&gt;
&lt;li&gt;メッセージはサーバーに保存&lt;&#x2F;li&gt;
&lt;li&gt;クラウドバックアップ時は暗号化解除&lt;&#x2F;li&gt;
&lt;li&gt;URL preview等の機能利用時はサーバーに内容送信&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;※4: 法執行機関への開示可能情報(doc.3)
&lt;ul&gt;
&lt;li&gt;7日分のテキストチャット履歴&lt;&#x2F;li&gt;
&lt;li&gt;アカウント情報&lt;&#x2F;li&gt;
&lt;li&gt;通信ログ&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;判断は以下の[LINEの公式ドキュメント]より確認しています。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;暗号化ホワイトペーパー(doc.1)&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-linewhitepaper-1&quot;&gt;&lt;a href=&quot;#fn-linewhitepaper&quot;&gt;3&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;terms2.line.me&#x2F;globalnews_PP&#x2F;sp&quot;&gt;プライバシーポリシー&lt;&#x2F;a&gt;(doc.2)&lt;&#x2F;li&gt;
&lt;li&gt;透明性レポート(doc.3)&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-linecorp-1&quot;&gt;&lt;a href=&quot;#fn-linecorp&quot;&gt;4&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;私自身は&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;threema.ch&#x2F;en&quot;&gt;Threema&lt;&#x2F;a&gt;を使用しています。&lt;&#x2F;p&gt;
&lt;section class=&quot;footnotes&quot;&gt;
&lt;ol class=&quot;footnotes-list&quot;&gt;
&lt;li id=&quot;fn-1&quot;&gt;
&lt;p&gt;この場合「プライバシー」と呼ぶのが適当かわかりませんが。 &lt;a href=&quot;#fr-1-1&quot;&gt;↩&lt;&#x2F;a&gt; &lt;a href=&quot;#fr-1-2&quot;&gt;↩2&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li id=&quot;fn-2&quot;&gt;
&lt;p&gt;2021年のZホールディングとの経営統合で、トークの画像などの情報が韓国の
サーバーでホスティングされていたり、通報確認などが中国企業に委託されてい
たり、このようなことが「第三国」としかレポートされていなかったりと透明性の観
点で問題がありました。現在は解消されたと報告されていますが。 &lt;a href=&quot;#fr-2-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li id=&quot;fn-linewhitepaper&quot;&gt;
&lt;p&gt;元のホワイトペーパー: https:&#x2F;&#x2F;scdn.line-apps.com&#x2F;stf&#x2F;linecorp&#x2F;en&#x2F;csr&#x2F;line-encryption-whitepaper-ver2.1.pdf は現在アクセスできません &lt;a href=&quot;#fr-linewhitepaper-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li id=&quot;fn-linecorp&quot;&gt;
&lt;p&gt;元のレポートページは削除されました &lt;a href=&quot;#fr-linecorp-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;&#x2F;section&gt;
</content>
        <summary type="html">市川強盗傷害事件で犯人たちがSignalを使っていたということで、「SIgnalは危険アプリ」とか言い出すバカがいそうなのでまとめてみました。</summary>
        </entry><entry xml:lang="en">
        <title>メインブログのAWS移行</title>
        <published>2024-10-21T00:00:00+00:00</published>
        <updated>2024-10-21T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2024/10/blog-hosted-on-aws/" type="text/html"/>
        <id>https://codedchords.dev/blog/2024/10/blog-hosted-on-aws/</id>
        
            <content type="html">&lt;p&gt;特に困っていたわけではありませんが、デプロイの自動化していると環境の違いで悩むこともあるのでローカルで生成したものをアップロードしようかなという気まぐれです。&lt;&#x2F;p&gt;
&lt;p&gt;試算では以下の程度の月額です。大きく外れたらまた戻すかもしれません。&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;サービス&lt;&#x2F;th&gt;&lt;th&gt;コスト項目&lt;&#x2F;th&gt;&lt;th&gt;月間コスト (USD)&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;S3&lt;&#x2F;td&gt;&lt;td&gt;ストレージ&lt;&#x2F;td&gt;&lt;td&gt;$0.0075&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;S3&lt;&#x2F;td&gt;&lt;td&gt;GET リクエスト&lt;&#x2F;td&gt;&lt;td&gt;$0.0012&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;ACM&lt;&#x2F;td&gt;&lt;td&gt;証明書&lt;&#x2F;td&gt;&lt;td&gt;$0&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;CloudFront&lt;&#x2F;td&gt;&lt;td&gt;データ転送&lt;&#x2F;td&gt;&lt;td&gt;$0.765&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;CloudFront&lt;&#x2F;td&gt;&lt;td&gt;HTTPS リクエスト&lt;&#x2F;td&gt;&lt;td&gt;$0.00225&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;合計&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;td&gt;&lt;&#x2F;td&gt;&lt;td&gt;&lt;strong&gt;$0.78&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
</content>
        <summary type="html">メインブログを CloudflareからAWS S3に移行してみました。</summary>
        </entry><entry xml:lang="en">
        <title>OpenAI o1-preview</title>
        <published>2024-09-17T00:00:00+00:00</published>
        <updated>2024-09-17T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2024/09/o1-preview/" type="text/html"/>
        <id>https://codedchords.dev/blog/2024/09/o1-preview/</id>
        
            <content type="html">&lt;p&gt;Currently evaluating OpenAI&#x27;s o1-preview. Although it is said that it is not
always more accurate than GPT-4o, when checked with the &quot;[World Model](https:
&#x2F;&#x2F;github.com&#x2F;SingularitySociety&#x2F;WorldModels&#x2F;)&quot;. It collects problems that
LLMs struggle with, o1-preview correctly solves questions like the following
that GPT-4o gets wrong.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Q1. What happens if you push a door labeled &quot;Pull&quot; from the opposite side?&lt;&#x2F;li&gt;
&lt;li&gt;Q2. A cotton candy is 8 centimeters tall, and a brick is 7 centimeters tall. If you place the brick on top of the cotton candy, what is the total height?&lt;&#x2F;li&gt;
&lt;li&gt;Q3. I left a wallet on a park bench near Shibuya Station for three hours. On that day, the temperature exceeded 39 degrees Celsius, and the wallet was exposed to direct sunlight. What happens to the wallet?&lt;&#x2F;li&gt;
&lt;li&gt;Q4. Do man-eating tigers live in unexplored jungles?&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;OpenAIのo1-previewを現在評価しています。GPT-4oより常に精度が高いわけではないと言われていますが、LLMが苦手な問題を集めた「&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;SingularitySociety&#x2F;WorldModels&#x2F;&quot;&gt;World Model&lt;&#x2F;a&gt;」で確認すると、GPT-4oで不正解となる次のような問題をo1-previewでは正確に解いてしまいます。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Q1.「引く」と書かれたドアを反対側から押すとどうるか？&lt;&#x2F;li&gt;
&lt;li&gt;Q2. 綿菓子の高さは8センチ、レンガの高さは7センチである。綿菓子の上にレ
ンガを置くと、全体の高さは何センチになるか？&lt;&#x2F;li&gt;
&lt;li&gt;Q3. 渋谷駅近くの公園のベンチに財布を3時間置き忘れた。
その日は気温が39度を超え、財布は直射日光にさらされていた。
財布はどうなるか？&lt;&#x2F;li&gt;
&lt;li&gt;Q4. 前人未到のジャングルに人喰い虎は生息しているか？&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</content>
        <summary type="html">OpenAIのo1-previewを現在評価しています。</summary>
        </entry><entry xml:lang="en">
        <title>生成AIハイプ・サイクル</title>
        <published>2024-09-11T00:00:00+00:00</published>
        <updated>2024-09-11T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2024/09/ai-hype-cycle/" type="text/html"/>
        <id>https://codedchords.dev/blog/2024/09/ai-hype-cycle/</id>
        
            <content type="html">&lt;p&gt;幻滅期に入っているとも言われますが、「マルチモーダル」はAIの使い勝手を劇的に変えてくれます。
すでに業界をリードするOpenAI&#x2F;Microsoft、Google、Anthropicの御三家は「マルチモーダル」をリリース済みですが、やはりOpenAIの使い勝手がよいようでです。&lt;&#x2F;p&gt;
&lt;blockquote cite=&quot;https:&#x2F;&#x2F;japan.zdnet.com&#x2F;article&#x2F;35223718&#x2F;&quot;&gt;
  同ハイプ・サイクルにおいて、「マルチモーダル生成 AI」は「オープンソースの
  大規模言語モデル（LLM）」とともに、「早期に採用することで顕著な競争優位性
  と市場投入までの期間短縮をもたらす可能性があるテクノロジー」として取り上げ
  られている。その上で、両技術とも今後 5 年以内に組織に大きな影響を及ぼす可
  能性を秘めているとしている。
  &lt;footer&gt;
    &lt;cite&gt;
      &lt;a href=&quot;https:&#x2F;&#x2F;japan.zdnet.com&#x2F;article&#x2F;35223718&#x2F;&quot;&gt;
        ZDNET - ガートナー、「生成 AI のハイプ・サイクル：2024 年」を発表
      &lt;&#x2F;a&gt;
    &lt;&#x2F;cite&gt;
  &lt;&#x2F;footer&gt;
&lt;&#x2F;blockquote&gt;
</content>
        <summary type="html">ガートナージャパンは9月10日、「生成AIのハイプ・サイクル：2024年」を発表したようです。</summary>
        </entry><entry xml:lang="en">
        <title>AWS ALBの脆弱性？</title>
        <published>2024-08-28T00:00:00+00:00</published>
        <updated>2024-08-28T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2024/08/vulnerability-aws-alb/" type="text/html"/>
        <id>https://codedchords.dev/blog/2024/08/vulnerability-aws-alb/</id>
        
            <content type="html">&lt;blockquote&gt;
&lt;p&gt;First, the attacker creates their own ALB instance with authentication
configured in their account. The attacker then uses this ALB to sign a
token they fully control. Next, the attacker alters the ALB configuration
and sets the issuer field to the victim&#x27;s expected issuer. AWS
subsequently signs the attacker&#x27;s forged token with the victim&#x27;s issuer.
Finally, the attacker uses this minted token against the victim&#x27;s
application, bypassing both authentication and authorization.&lt;&#x2F;p&gt;
&lt;p&gt;まず、攻撃者は自身のアカウント内に認証を設定した独自の ALB インスタンスを作成します。
次に、この ALB を使用して、攻撃者が完全に制御できるトークンに署名します。
その後、攻撃者は ALB の設定を変更し、発行者フィールドを被害者が期待する発行者に設定します。
AWS はその結果、攻撃者が偽造したトークンに対して、被害者の発行者として署名を行います。
最後に、攻撃者はこの生成されたトークンを使用して被害者のアプリケーションに対して攻撃を仕掛け、認証と認可の両方を回避します。&lt;&#x2F;p&gt;
&lt;cite&gt;
  [ALBeast Security Advisory by Miggo Research |
  Miggo](https:&#x2F;&#x2F;www.miggo.io&#x2F;resources&#x2F;albeast-security-advisory-alb-vulnerability)
&lt;&#x2F;cite&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;「AWS ALBの脆弱性」と騒がれているけれど、普通にIssuerの検証、JWTトークンの検証、ALBのトラフィックの制限、セキュリティグループの設定をやっていれば関係なくない？「AWS ALBの&lt;strong&gt;ベストプラクティスを無視した間抜けが作ったアプリ&lt;&#x2F;strong&gt;の脆弱性」では？&lt;&#x2F;p&gt;
</content>
        <summary type="html">AWS ALBの脆弱性と騒がれているが・・・</summary>
        </entry><entry xml:lang="en">
        <title>こだわりのNostr Pubkeyを手に入れる</title>
        <published>2024-08-25T00:00:00+00:00</published>
        <updated>2024-08-25T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2024/08/pubkey-of-nostr/" type="text/html"/>
        <id>https://codedchords.dev/blog/2024/08/pubkey-of-nostr/</id>
        
            <content type="html">&lt;p&gt;NostrでVanity pubkeyのMiningをやってみました。
プリフィックスに&lt;code&gt;yostos&lt;&#x2F;code&gt;と近い&lt;code&gt;y0st0s&lt;&#x2F;code&gt;を得るため、&lt;code&gt;rana&lt;&#x2F;code&gt;を使って数時間Miningしました。&lt;&#x2F;p&gt;
&lt;p&gt;得られた、Pubkeyが&lt;code&gt;npub1y0st0svvu5xg6dvswx7dz5m2p7004kmvsx6n22w4yjp3l6fa3mvsef2zz7&lt;&#x2F;code&gt;で、npub1に続く部分が&lt;code&gt;y0st0s&lt;&#x2F;code&gt;となっています。自己満足ですが。&lt;&#x2F;p&gt;
&lt;p&gt;ranaのインストールと使い方は次の通りです。Rustの実行環境が事前に必要です。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;cargo&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; install rana&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;rana&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; --vanity-n-prefix y0st0s&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;Started&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt; mining process for vanity bech32 prefix[es]: &amp;#39;npub1[&amp;quot;y0st0s&amp;quot;]&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; (estimated&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; pow:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 24&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;Benchmarking&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; of cores disabled for vanity npub key upon proper calculation.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;Mining&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; using&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 14&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; cores...&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;&amp;lt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;gt;&amp;gt;&amp;lt;&amp;lt;&amp;gt;&amp;gt;&amp;lt;&amp;lt;&amp;gt;&amp;gt;&amp;lt;&amp;lt;&amp;gt;&amp;gt;&amp;lt;&amp;lt;&amp;gt;&amp;gt;&amp;lt;&amp;lt;&amp;gt;&amp;gt;&amp;lt;&amp;lt;&amp;gt;&amp;gt;&amp;lt;&amp;lt;&amp;gt;&amp;gt;&amp;lt;&amp;lt;&amp;gt;&amp;gt;&amp;lt;&amp;lt;&amp;gt;&amp;gt;&amp;lt;&amp;lt;&amp;gt;&amp;gt;&amp;lt;&amp;lt;&amp;gt;&amp;gt;&amp;lt;&amp;lt;&amp;gt;&amp;gt;&amp;lt;&amp;lt;&amp;gt;&amp;gt;&amp;lt;&amp;lt;&amp;gt;&amp;gt;&amp;lt;&amp;lt;&amp;gt;&amp;gt;&amp;lt;&amp;lt;&amp;gt;&amp;gt;&amp;lt;&amp;lt;&amp;gt;&amp;gt;&amp;lt;&amp;lt;&amp;gt;&amp;gt;&amp;lt;&amp;lt;&amp;gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;Vanity npub found: y0st0s&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;Found matching Nostr public key:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;Hex public key: 23e0b7c18ce50c8d359071bcd1536a0f9efadb6c81b53529d524831fe93d8ed9&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;Hex private key: @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;Npub public key: npub1y0st0svvu5xg6dvswx7dz5m2p7004kmvsx6n22w4yjp3l6fa3mvsef2zz7&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;Nsec private key: nsec1@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;2597711770 iterations (about 2x10^9 hashes) in 3433 seconds. Avg rate 756688 hashes&#x2F;second&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;プリフィックスに指定する桁数が増えるほどマイニングに時間がかかるので注意しましょう。上記の例ではM3 MAXのMacbook Proで1時間ほどかかりました。&lt;&#x2F;p&gt;
&lt;p&gt;また、PubkeyはNative SegWit(Bech32)でエンコードされており、小文字でl,b,i,oを除いた32文字しか使えません。これらの文字については数字などに置き換えて指定する必要があります（yostos-&amp;gt;y0st0sなど）&lt;&#x2F;p&gt;
</content>
        <summary type="html">Nostrで自分の好きなPubkeyを入手するためにがんばってみました。</summary>
        </entry><entry xml:lang="en">
        <title>コマンドラインで画像のExif修正</title>
        <published>2024-08-23T00:00:00+00:00</published>
        <updated>2024-08-23T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2024/08/exiftool/" type="text/html"/>
        <id>https://codedchords.dev/blog/2024/08/exiftool/</id>
        
            <content type="html">&lt;p&gt;デジカメの日付の設定を間違えExifの日付を修正したかったが、
AppStoreから余計なアプリをインストールしたくなかったので、Homebrewでexiftoolをインストールして修正。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# Install exiftool using Homebrew&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;brew&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; install exiftool&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# Confirm dates of exif&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;exiftool&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; R0000001.jpg&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;    ExifTool&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; Version Number         :&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 12.76&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;    File&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; Name                       : R0000001.JPG&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;    Directory&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;                       : .&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;    File&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; Size                       :&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 12&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; MB&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;    File&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; Modification Date&#x2F;Time     : 2024:08:26 12:42:29+09:00&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;    File&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; Access Date&#x2F;Time           : 2024:08:26 12:43:26+09:00&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;    File&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; Inode Change Date&#x2F;Time     : 2024:08:26 12:43:24+09:00&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;    File&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; Permissions                : -rwx------&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;    File&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; Type                       : JPEG&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;    File&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; Type Extension             : jpg&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;    MIME&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; Type                       : image&#x2F;jpeg&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;    Exif&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; Byte Order                 : Little-endian&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; (Intel,&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; II&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    (&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;Output&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; truncated for brevity&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# Modify dates of exif&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;exiftool&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-punctuation z-definition z-string&quot;&gt; -Alldates=&amp;#39;2024:08:23 12:11:00&amp;#39; -overwrite_original .&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt;*&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;</content>
        <summary type="html">デジカメの日付の設定を間違えたので、Exifの日付をコマンドラインで一括修正する方法を見つけました。</summary>
        </entry><entry xml:lang="en">
        <title>AWS CodeCommit新規受付凍結の影響について</title>
        <published>2024-08-13T00:00:00+00:00</published>
        <updated>2024-08-13T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2024/08/codecommit-impact/" type="text/html"/>
        <id>https://codedchords.dev/blog/2024/08/codecommit-impact/</id>
        
            <content type="html">&lt;blockquote&gt;
  Amazon&#x27;s recent decision to stop accepting new users for several cloud
  services caught some customers, partners and even a few employees by surprise.
  (Amazon
  が展開中の複数のクラウドサービスについて新規ユーザー登録受付を中止したことで、顧客や協力企業の間で混乱が広がっている。)
  &lt;footer&gt;
    &lt;cite&gt;
      Business Insider -{&quot; &quot;}
      &lt;a href=&quot;https:&#x2F;&#x2F;www.businessinsider.com&#x2F;aws-deprioritized-cloud-services-surprising-customers-salespeople-2024-8&quot;&gt;
        Amazon decision to deprioritize 7 cloud services caught customers and
        even some salespeople by surprise
      &lt;&#x2F;a&gt;
    &lt;&#x2F;cite&gt;
  &lt;&#x2F;footer&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;以下の記事は、最近の報道などを見た個人的な意見です。既に中の人ではないので、この件に関しては報道以上の情報は持ち合わせていません。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;サービス凍結の状況&quot;&gt;サービス凍結の状況&lt;&#x2F;h2&gt;
&lt;p&gt;同記事によると、次のように説明されている模様です。&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;As the public outcry grew, AWS&#x27;s chief evangelist Jeff Barr wrote a short X post on Tuesday to explain that the company decided to &quot;discontinue new access to a small number of services,&quot; but it would continue running them in a secure environment.&lt;&#x2F;p&gt;
&lt;p&gt;関係者から懸念の声が高まったことを受け、AWSのバイスプレジデント兼チーフエバンジェリストを務めるジェフ・バー氏は7月30日のX（旧Twitter）投稿を通じて詳細な事実を説明するとともに、今後の対応を明らかにした。&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;これまで使ってきたユーザーはそのまま使用でき、新規ユーザーはGitHubなど別のソリューションを選択すればよいのですぐに何か問題となる訳でありません。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;新規受付凍結の影響&quot;&gt;新規受付凍結の影響&lt;&#x2F;h2&gt;
&lt;p&gt;この変更により直近大きな影響はなさそうですが、顧客としては不安でしょう。&lt;&#x2F;p&gt;
&lt;p&gt;既存ユーザーに対してはサポートを継続すると言われていますが、ほとんどの顧客は遠からずこれらのサービスが終了すると考えているでしょう。つまり、顧客は将来のサービス終了に備えた対応を迫られています。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;aws.amazon.com&#x2F;jp&#x2F;blogs&#x2F;devops&#x2F;how-to-migrate-your-aws-codecommit-repository-to-another-git-provider&#x2F;&quot;&gt;AWSのブログ&lt;&#x2F;a&gt;でリポジトリーの移行方法が紹介されていますが、CodeCommitやCloud9などのツールは開発プロセスの中に組み込まれて使用しているので、最低でも次のような対応が必要です。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;リポジトリーの移行&lt;&#x2F;li&gt;
&lt;li&gt;ユーザーの移行&lt;&#x2F;li&gt;
&lt;li&gt;CI&#x2F;CDの組み直し&lt;&#x2F;li&gt;
&lt;li&gt;開発プロセスの対応変更&lt;&#x2F;li&gt;
&lt;li&gt;社内の移管手続きの変更&lt;&#x2F;li&gt;
&lt;li&gt;開発者や運用者の再教育&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;ちょっとした組織横断のプロジェクトになりそうです。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;何が悪かったのか？&quot;&gt;何が悪かったのか？&lt;&#x2F;h2&gt;
&lt;p&gt;第一の問題は、AWSがCodeCommitやCloud9のサービスの重要性をAWSが図り損ねたことでしょう。&lt;&#x2F;p&gt;
&lt;p&gt;想像するに、CodeCommitやCloud9はそれほど利用者が多くなかったのでしょう。
ユーザーの利用度が低い、サービス提供側から見ると金を生まないサービスを統廃合していくのは当たり前の話です。&lt;&#x2F;p&gt;
&lt;p&gt;これが本番環境のRuntimeだけに関わる問題であれば、ここまでの問題にならなかったかもしれません。
ところが、CodeCommitやCloud9などは企業ITの組織やプロセスに深く関わるので、サービスの移行だけでなく人やプロセスの移行も必要です。
少数かもしれませんが、AWSを信じてCodeCommitやCloud9を利用していた企業は多大な移行コストが必要となります。&lt;&#x2F;p&gt;
&lt;p&gt;その認識がAWSには足りてなかったのではないかと思います。
アプリ開発の側の人だったので偏見かもしれませんが、どうもインフラ屋さんというのはこういう部分のセンスが足りていないのではないかと思うことがよくあります。&lt;&#x2F;p&gt;
&lt;p&gt;結果として、Business Insiderが報じるよう、AWS自身も以下のようは羽目になってしまっています。&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;The company is trying to keep supporting clients while signaling that these offerings are no longer a strategic priority.&lt;&#x2F;p&gt;
&lt;p&gt;同社は、これらのサービスがもはや戦略的優先事項ではないことを示しながら、顧客のサポートを続けようとしている。&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;2点目は、これらの決定に至るAWS社内での連携の問題でしょう。&lt;&#x2F;p&gt;
&lt;p&gt;AWS CLIの&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;aws&#x2F;aws-cli&#x2F;blob&#x2F;v2&#x2F;CHANGELOG.rst&quot;&gt;CHANGE LOG&lt;&#x2F;a&gt;を見ると、7月26日にCommitされた2.17.18のコメントに以下のように記述されています。これを受けて一部の顧客が気付いて徐々に騒ぎが大きくなっていったようです。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;api-change:`codecommit`: CreateRepository API now throws OperationNotAllowedException when the account has been restricted from creating a repository.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;実際には6月6日から新規顧客への制限を加えていたという話もあります。当然これらの決定は更に数ヶ月前には行われていたことでしょう。一方でBusiness Insiderが報じるようにAWS内部でも十分に周知されないまま決定されたようです。&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;It turns out that even some of Amazon&#x27;s own salespeople were not aware of the change until after it was made public late last week.&lt;&#x2F;p&gt;
&lt;p&gt;なお、アマゾンの営業部門の中には事前に何も聞かされておらず、同社が先週末に受付中止を公表した時点で初めてその事実を知った従業員が複数いることも分かった。&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;アグレッシブな機能の改善は美点でもあり機能やサービスをどんどん追加している時はよかったかもしれませんが、ある程度利用が定着した段階に入っているこれからはこれまでのようなカジュアルな変更は難しいのかもしれません。&lt;&#x2F;p&gt;
</content>
        <summary type="html">Business Insider などを読んでいるとAWSのCodeCommitやCloud9の新規受付凍結は、米国でもかなり問題になっている模様。</summary>
        </entry><entry xml:lang="en">
        <title>Software Development Using Generative AI</title>
        <published>2024-08-09T00:00:00+00:00</published>
        <updated>2024-08-09T00:00:00+00:00</updated>
        <author>
            <name>Toshiyuki Yoshida</name>
        </author>
        <link rel="alternate" href="https://codedchords.dev/blog/2024/08/software-development-using-ai/" type="text/html"/>
        <id>https://codedchords.dev/blog/2024/08/software-development-using-ai/</id>
        
            <content type="html">&lt;p&gt;日本語は下の方に。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;Dramatic_Cost_Reduction&quot;&gt;Dramatic Cost Reduction&lt;&#x2F;h2&gt;
&lt;p&gt;The use of generative AI has dramatically reduced the costs of producing images and music.
For example, tasks like illustration creation and music creation (using services like Udio and Suno) previously required specialists.
These tasks can now be done by individuals in about five minutes using generative AI-powered services.&lt;&#x2F;p&gt;
&lt;p&gt;In software development, the use of generative AI for development support is also spreading.
Many developers are likely using tools like Github Copilot.&lt;&#x2F;p&gt;
&lt;p&gt;However, applications of generative AI in software development are progressing beyond mere coding support.
For example, I recently changed the static site generator for my main blog, which required converting the metadata of several hundred articles.
I wrote a conversion program in Python.
But by providing ChatGPT with the prerequisites and requirements, I only needed to make about 10% modifications to the generated code.&lt;&#x2F;p&gt;
&lt;p&gt;This example shows that generative AI can shoulder not only development support but also the creation of software itself.
It is similar to image and music production.
In the example above, what would have taken about two weeks if outsourced to a development vendor was reduced significantly.
This reduction brought the work down to about 30 minutes using generative AI.&lt;&#x2F;p&gt;
&lt;p&gt;The cost is only 0.6%.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;What_Generative_AI_Software_Development_Brings&quot;&gt;What Generative AI Software Development Brings&lt;&#x2F;h2&gt;
&lt;p&gt;The rationale for traditional software development was that it could reduce the
workload of many people through repeated use. Therefore, single-use software
development for specific users was not permitted.&lt;&#x2F;p&gt;
&lt;p&gt;However, there is a world where single-use software development has been
allowed: the realm of data science. This is because of the unique nature of
datasets and the need for trial and error, where speed is prioritized over
reuse. The most significant reason is that the benefits gained from single-use
software development outweigh the costs.&lt;&#x2F;p&gt;
&lt;p&gt;By leveraging generative AI, it becomes possible to reduce costs in general
software development similarly. This means that even single-use software
development for one user, which does not contribute to reducing the workload of
many, becomes feasible.&lt;&#x2F;p&gt;
&lt;p&gt;In other words, we are entering an era where problems that could be solved by software but were left unaddressed due to development costs.
These problems can now be resolved quickly using generative AI for software development.&lt;&#x2F;p&gt;
&lt;p&gt;In practice, when you ask ChatGPT a question like &quot;What is the date 100 days after August 9, 2024?&quot;, a single-use Python code is generated.
This specialized code is executed behind the scenes to solve this specific problem.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;python&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;from&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; datetime&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; import&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; datetime&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; timedelta&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# Starting date&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;start_date&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt; datetime&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;2024&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 8&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 8&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# Calculate the date 100 days later&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;end_date&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; start_date&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; +&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt; timedelta&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt;days&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;100&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;end_date&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;strftime&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;#39;%Y-%m-&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-format z-placeholder z-other z-python&quot;&gt;%d&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;Differences_from_RPA_and_No-Code&quot;&gt;Differences from RPA and No-Code&lt;&#x2F;h2&gt;
&lt;p&gt;Similar technologies include RPA and no-code solutions. Many companies have
adopted these technologies, riding the wave of the DX trend.&lt;&#x2F;p&gt;
&lt;p&gt;Both have the effect of lowering software development costs, but there are
significant differences in their technology and implementation effects.&lt;&#x2F;p&gt;
&lt;p&gt;From a technical perspective, generative AI software development involves custom development by AI according to requirements.
RPA and no-code solutions appear to meet user requests, but in reality, only pour parameters into pre-made software provided by vendors.
Therefore, what can be achieved must be based on the templates of the pre-made software.&lt;&#x2F;p&gt;
&lt;p&gt;More importantly than these technical differences is the impact of their implementation.
In many cases with RPA and no-code solutions, user departments develop the software themselves.
This happens when they become frustrated with waiting for the development department.&lt;&#x2F;p&gt;
&lt;p&gt;This means that non-developers are creating reusable software, or corporate software assets, which is a nightmare.
Years later, the software will likely become a maintenance burden due to the users&#x27; transfer or the vendors&#x27; product lifecycle.&lt;&#x2F;p&gt;
&lt;p&gt;In contrast, single-use software development using generative AI emphasizes the outcomes rather than the software itself.
Thus, the specifics of the software do not matter.
Even so, a verifiable artifact in the form of &quot;source code&quot; is created, making it a completely transparent process (white box).&lt;&#x2F;p&gt;
&lt;h2 id=&quot;Conclusion&quot;&gt;Conclusion&lt;&#x2F;h2&gt;
&lt;p&gt;Seeing companies that claim to have achieved &quot;DX&quot; by introducing RPA and no-code solutions gives me chills.
In contrast, companies should recognize the new application methods of software development.
These methods allow generative AI to be used to solve problems on the spot, similar to the approach taken by data scientists.
This approach is similar to the methods employed by data scientists.&lt;&#x2F;p&gt;
&lt;p&gt;In such a world, engineers with the ability to read source code will become
increasingly necessary. Companies currently investing in RPA and no-code
solutions should be cautious, as they may be going against the trend.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;劇的なコスト削減&quot;&gt;劇的なコスト削減&lt;&#x2F;h2&gt;
&lt;p&gt;生成系AIの活用により、画像や音楽の制作コストが劇的に削減されています。例えば、
これまで専門家に依頼しなければならなかったイラスト作成（MidjourneyやDALL-E 2な
ど）や音楽作成（UdioやSunoなど）を、生成系AIを取り入れたサービスを使うことで、
自分で5分ほどで望みの画像や音楽を制作できます。&lt;&#x2F;p&gt;
&lt;p&gt;ソフトウェア開発においても、生成系AIを活用した開発支援が広がってきています。実
際に、Github Copilotのようなツールを使用している開発者も多いでしょう。&lt;&#x2F;p&gt;
&lt;p&gt;しかし、これらのコーディング支援とは別の次元で、ソフトウェア開発への応用も進ん
でいます。例えば、最近私はメインブログの静的サイトジェネレータを変更しました
が、それに伴い記事のメタデータの変換が必要でした。数百ある記事の変換プログラム
をPythonで書きましたが、ChatGPTに前提と要件を伝えて生成されたコードをベースに、
10%程度の修正するだけで済みました。&lt;&#x2F;p&gt;
&lt;p&gt;これは、開発作業の支援だけでなく、画像や音楽の制作と同様にソフトウェア制作その
ものを生成系AIに肩代わりさせることができる例です。上記の例では、開発ベンダーに
依頼すると2週間ほどの時間がかかるところを、生成系AIを使って自分でコードを作成す
れば30分程度で済みます。&lt;&#x2F;p&gt;
&lt;p&gt;コストは0.6%で済んでしまいます。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;生成系AIによるソフトウェア開発がもたらすもの&quot;&gt;生成系AIによるソフトウェア開発がもたらすもの&lt;&#x2F;h2&gt;
&lt;p&gt;従来のソフトウェア開発のRationale（根拠）は、何度も使用されることで多くの人の作
業を軽減できることにありました。そのため、特定のユーザーのための使い切りのソフ
トウェア開発は許されませんでした。&lt;&#x2F;p&gt;
&lt;p&gt;しかし、使い切りのソフトウェア開発が許されてきた世界があります。それはデータサ
イエンスの領域です。これは、データセットの特異性やそれに伴う試行錯誤の必要性、
再利用より迅速性が重視されたためです。最も大きな理由は、使い切りのソフトウェア
開発のコストに対して得られる成果が大きいからです。&lt;&#x2F;p&gt;
&lt;p&gt;生成系AIを活用すれば、一般的なソフトウェア開発でも同様にコスト削減が可能とな
り、多くの人の作業軽減に貢献しない、一人のユーザーのためだけの使い切りのソフト
ウェアを開発することも可能になります。&lt;&#x2F;p&gt;
&lt;p&gt;つまり、これまで開発コストを理由にソフトウェアで解決出来る問題が放置されていた
状況を「生成系AI使って、ささっとソフトウェア開発をして解決すればよい」という時
代になってきていると感じます。&lt;&#x2F;p&gt;
&lt;p&gt;実際、ChatGPTで「2024年8月9日の100日後は何日？」というような質問の回答を作るの
に、裏では以下のようはこの問題に特化した使い切りのPythonコードが生成されて実行
されています。&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;python&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;from&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; datetime&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; import&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; datetime&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; timedelta&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# Starting date&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;start_date&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt; datetime&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;2024&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 8&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 8&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# Calculate the date 100 days later&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;end_date&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; start_date&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; +&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt; timedelta&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt;days&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;100&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;end_date&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;strftime&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-string&quot;&gt;&amp;#39;%Y-%m-&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-format z-placeholder z-other z-python&quot;&gt;%d&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;RPAやノーコードとの違い&quot;&gt;RPAやノーコードとの違い&lt;&#x2F;h2&gt;
&lt;p&gt;似たような技術にはRPAやノーコードがあります。DXの流行に乗って、これらを導入した
企業も多いと思います。&lt;&#x2F;p&gt;
&lt;p&gt;どちらもソフトウェア開発コストを下げるという効果がありますが、その技術と導入効
果の面で大きな違いがあります。&lt;&#x2F;p&gt;
&lt;p&gt;技術面で見ると、生成系AIによるソフトウェア開発では要件に従いAIよるソフトウェア
のカスタム開発が行われています。しかし、RPAやノーコードではユーザーのリクエストに沿っ
て必要なソフトウェアを実現しているように見えますが、実際にはベンダーが用意した
ソフトウェアにパラメータを流し込んでいるだけです。そのため、実現できることもあ
らかじめ用意されたソフトウェアのひな形を意識した要件に落とし込む必要があります。&lt;&#x2F;p&gt;
&lt;p&gt;こういった技術的な違いよりも、問題はその導入効果です。
RPAやノーコードで多く行われているのは、開発要望が開発部門のバックログ
いつまでも実現されないと
業を煮やしたユーザー部門が自身で開発するというパターンです。これは使い回すソフト
ウェア、つまり企業のソフトウェア資産を開発者でない素人が開発してしまうことを意
味します。悪夢でしかありません。数年後には開発したユーザーの異動やベンダーの製
品ライフサイクルから、メンテナンスできないソフトウェアという負の遺産になってい
ることでしょう&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-1-1&quot;&gt;&lt;a href=&quot;#fn-1&quot;&gt;1&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;。&lt;&#x2F;p&gt;
&lt;p&gt;一方で生成系AIによる使い切りソフトウェア開発は生成したソフトウェアそのもので
はなく成果が重視されるため、どのようなソフトウェアだったかは問題になりま
せん。それでも、「ソースコード」という検証可能な成果物が作成されるため、完全に
透明な状態（ホワイトボックス）です。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;まとめ&quot;&gt;まとめ&lt;&#x2F;h2&gt;
&lt;p&gt;RPAやノーコードのソリューションを導入して「DX実現」としている企業の将来を思うと
暗い未来しか想像できません。&lt;&#x2F;p&gt;
&lt;p&gt;一方で従来のソフトウェア開発とは異なる、これまでデータサイエンティストが取り組
んできたようなアプローチ、つまるソフトウェア開発によるその場の問題解決が生成系
AIを使うと可能になるので、新しいソフトウェアの応用方法として企業はしっかりと認
知すべきだと思います。&lt;&#x2F;p&gt;
&lt;p&gt;こういった世界ではソースコードを読む能力を持ったエンジニアはますます必要になっ
てくるので、そういった意味でもRPAやノーコードに取り組んでいる企業は逆流している
ので気をつけたほうがよいと思います。&lt;&#x2F;p&gt;
&lt;section class=&quot;footnotes&quot;&gt;
&lt;ol class=&quot;footnotes-list&quot;&gt;
&lt;li id=&quot;fn-1&quot;&gt;
&lt;p&gt;「サーバー型RPAならば集中管理できてそうはならない」という意見もあり
ます。それならばIT部門が開発して管理すればよくベンダー依存のランタイム
上でシステムを構築する意味がないのではないでしょうか？　もっともここに
AIを応用すると世界が変わる可能性はありますが、現時点ではまだ予測不能で
す。 &lt;a href=&quot;#fr-1-1&quot;&gt;↩&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;&#x2F;section&gt;
</content>
        <summary type="html">Recently, I had a conversation with someone about software development using ChatGPT, and a few things caught my attention. I decided to summarize my thoughts here.</summary>
        </entry>
</feed>
