<?xml version="1.0"?>
<rss version="2.0"
     xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>JBake</title>
        <link >https://cheroliv.com/</link>
        <atom:link href="https://cheroliv.com/feed.xml" rel="self" type="application/rss+xml" />
        <description>JBake Bootstrap テンプレート</description>
        <language>en-gb</language>
        <pubDate>Thu, 8 Oct 2026 11:37:55 +0000</pubDate>
        <lastBuildDate>Thu, 8 Oct 2026 11:37:55 +0000</lastBuildDate>

        <item>
            <title>HyperFrames-Gradle : AsciiDocをMP4動画に変換</title>
            <link >https://cheroliv.com/blog/2026/0126_hyperframes_asciidoc_video_post.html</link>
            <pubDate>Sun, 31 May 2026 00:00:00 +0000</pubDate>
            <guid isPermaLink="false">blog/2026/0126_hyperframes_asciidoc_video_post.html</guid>
            <description>&amp;lt;div id=&amp;quot;toc&amp;quot; class=&amp;quot;toc&amp;quot;&amp;gt;
&amp;lt;div id=&amp;quot;toctitle&amp;quot;&amp;gt;Table des matières&amp;lt;/div&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel1&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_ビデオパイプラインの穴&amp;quot;&amp;gt;ビデオパイプラインの穴&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_hyperframes_エンジン&amp;quot;&amp;gt;HyperFrames : エンジン&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_プラグインのアーキテクチャ&amp;quot;&amp;gt;プラグインのアーキテクチャ&amp;lt;/a&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel2&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_4段階のパイプライン&amp;quot;&amp;gt;4段階のパイプライン&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_asciidoc_dsl&amp;quot;&amp;gt;AsciiDoc DSL&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_node_js_ブリッジ&amp;quot;&amp;gt;Node.js ブリッジ&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_2つのビデオプラグイン2つの使い方&amp;quot;&amp;gt;2つのビデオプラグイン、2つの使い方&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_ロードマップの6つのepic&amp;quot;&amp;gt;ロードマップの6つのEPIC&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_なぜそれが機能するのか&amp;quot;&amp;gt;なぜそれが機能するのか&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_結論_欠けているリンク&amp;quot;&amp;gt;結論 : 欠けているリンク&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_参考文献&amp;quot;&amp;gt;参考文献&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div id=&amp;quot;preamble&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;読了時間 : 8 minutes&amp;lt;/div&amp;gt;
&amp;lt;p&amp;gt;二週間前に、私は開始しました。&amp;lt;code&amp;gt;capsule-gradle&amp;lt;/code&amp;gt;— デッキを変換するプラグイン reveal.js を WebM ビデオカプセルに TTS 付きで。今日、私は新しいプラグインを追加します: &amp;lt;code&amp;gt;hyperframes-gradle&amp;lt;/code&amp;gt;. それは capsule-gradle が行わないことをしている： AsciiDoc を &amp;lt;strong&amp;gt;直接的に&amp;lt;/strong&amp;gt; MP4 動画に変換し、reveal.js を経由せずに。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;なぜこのプラグインが存在するのか、そしてそれが既存のものにどのように組み込まれるかを示します。 HeyGenのHyperFramesエンジンがコンテンツ制作パイプラインにもたらすもの&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_ビデオパイプラインの穴&amp;quot;&amp;gt;ビデオパイプラインの穴&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;私のドキュメンタリーパイプラインは2種類のビデオを生成します :&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;olist arabic&amp;quot;&amp;gt;
&amp;lt;ol class=&amp;quot;arabic&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;復習カプセル&amp;lt;/strong&amp;gt; (capsule-gradle) — WebM でキャプチャされた reveal.js のデッキと共に&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ol&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;narration TTS. モジュールの復習に最適です。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;olist arabic&amp;quot;&amp;gt;
&amp;lt;ol class=&amp;quot;arabic&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;アニメーションスライド&amp;lt;/strong&amp;gt; (slider-gradle) — インタラクティブな reveal.js HTML デッキのために&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ol&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;対面の講師。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;しかし、３番目のフォーマットが欠けています：&amp;lt;strong&amp;gt;スタンドアロン動画&amp;lt;/strong&amp;gt;。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;table class=&amp;quot;tableblock frame-all grid-all stretch&amp;quot;&amp;gt;
&amp;lt;colgroup&amp;gt;
&amp;lt;col style=&amp;quot;width: 5.5555%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 5.5555%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 5.5555%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 5.5555%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 5.5555%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 5.5555%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 5.5555%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 5.5555%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 5.5555%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 5.5555%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 5.5555%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 5.5555%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 5.5555%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 5.5555%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 5.5555%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 5.5555%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 5.5555%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 5.5565%;&amp;quot;&amp;gt;
&amp;lt;/colgroup&amp;gt;
&amp;lt;tbody&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;ユースケース&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;現在の解決策&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;不足&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;インストラクター用スライド&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;slider-gradle → reveal.js&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;�✅&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;カプセルの復習&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;capsule-gradle → WebM&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;✅&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;ティーザー動画&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;ない&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;�❌&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;アニメーション技術デモ&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;なし&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;�❌&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;ドキュメントからビデオへ&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;なし&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;❌&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/tbody&amp;gt;
&amp;lt;/table&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;最初のユースケースは重要です：自動的に生成するにはどうすればよいですか？ 60秒のビデオで、プロジェクトまたはモジュールを紹介し、GSAPアニメーションを使用して、 ナレーションTTS、およびバックグラウンドミュージック — すべて同じAsciiDocファイルから スライドはどうですか？&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;Capsule-gradleは応答できません：それには &amp;lt;strong&amp;gt;déjà&amp;lt;/strong&amp;gt; reveal.jsのデッキが必要です。 slider-gradle はこのデッキをうまく生成しますが、動画レンダリングのために設計されていません。 必要だったパイプライン &amp;lt;strong&amp;gt;direct&amp;lt;/strong&amp;gt; : AsciiDoc → ビデオ。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_hyperframes_エンジン&amp;quot;&amp;gt;HyperFrames : エンジン&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;見つけたhttps://github.com/heygen-com/hyperframes[ハイパーフレーム] il y a 数日間。これはヘイゲンによって作成されたオープンソースのフレームワーク（Apache 2.0）で AIビデオのユニコーン。GitHubで22,700の星。ピッチは 文 :&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;quoteblock&amp;quot;&amp;gt;
&amp;lt;blockquote&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;HTMLを書く。ビデオをレンダリング。エージェント向けに構築。&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/blockquote&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;原則：あなたは HTML を書きます（…と）`data-*`属性、あなたは参照します GSAP（または CSS、Lottie、Three.js…）のアニメーションで、エンジンがすべてを MP4 としてレンダリングします Puppeteer (ヘッドレス Chrome) + FFmpeg を介して。決定的な結果 : 同じ入力, 同じフレーム、同じビデオ。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-html hljs&amp;quot; data-lang=&amp;quot;html&amp;quot;&amp;gt;&amp;amp;lt;div id=&amp;quot;stage&amp;quot; data-composition-id=&amp;quot;intro&amp;quot; data-start=&amp;quot;0&amp;quot; data-width=&amp;quot;1920&amp;quot; data-height=&amp;quot;1080&amp;quot;&amp;amp;gt;
  &amp;amp;lt;video class=&amp;quot;clip&amp;quot; data-start=&amp;quot;0&amp;quot; data-duration=&amp;quot;6&amp;quot; data-track-index=&amp;quot;0&amp;quot;
         src=&amp;quot;background.mp4&amp;quot; muted playsinline&amp;amp;gt;&amp;amp;lt;/video&amp;amp;gt;

  &amp;amp;lt;h1 id=&amp;quot;title&amp;quot; class=&amp;quot;clip&amp;quot; data-start=&amp;quot;1&amp;quot; data-duration=&amp;quot;4&amp;quot; data-track-index=&amp;quot;1&amp;quot;&amp;amp;gt;
    Formation Docker &amp;amp;amp; Kubernetes
  &amp;amp;lt;/h1&amp;amp;gt;

  &amp;amp;lt;audio data-start=&amp;quot;0&amp;quot; data-duration=&amp;quot;6&amp;quot; data-track-index=&amp;quot;2&amp;quot;
         data-volume=&amp;quot;0.3&amp;quot; src=&amp;quot;music.wav&amp;quot;&amp;amp;gt;&amp;amp;lt;/audio&amp;amp;gt;

  &amp;amp;lt;script src=&amp;quot;https://cdn.jsdelivr.net/npm/gsap@3/dist/gsap.min.js&amp;quot;&amp;amp;gt;&amp;amp;lt;/script&amp;amp;gt;
  &amp;amp;lt;script&amp;amp;gt;
    const tl = gsap.timeline({ paused: true });
    tl.from(&amp;quot;#title&amp;quot;, { opacity: 0, y: 40, duration: 0.8 }, 1);
    window.__timelines = window.__timelines || {};
    window.__timelines.intro = tl;
  &amp;amp;lt;/script&amp;amp;gt;
&amp;amp;lt;/div&amp;amp;gt;&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;HyperFrames と Remotion の違いは何ですか？React なし、 bundler、JSXはなし。AIエージェントがネイティブに書ける素のHTML。 これは私のパイプラインに &amp;lt;strong&amp;gt;まさに&amp;lt;/strong&amp;gt; ぴったり合っています : planner-gradle と deepseek これは SPG/SPD プランからこの HTML を生成し、Gradle プラグインも使用できます それをMP4に変換できる&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_プラグインのアーキテクチャ&amp;quot;&amp;gt;プラグインのアーキテクチャ&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;hyperframes-gradle すべてのプラグインと同じパターンに従います： この &amp;lt;a href=&amp;quot;0124_architecture_plugin_gradle_racine_consommateur_independant_post.html&amp;quot;&amp;gt;pattern « 独立プラグイン + コンシューマー ルート 」&amp;lt;/a&amp;gt;.&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-text hljs&amp;quot; data-lang=&amp;quot;text&amp;quot;&amp;gt;hyperframes-gradle/
├── settings.gradle.kts          ← racine consommateur (dogfood)
├── build.gradle.kts              ← 3 lignes : apply plugin hyperframes
├── hyperframes-plugin/           ← BUILD INDÉPENDANT
│   ├── gradlew                    ← son propre wrapper
│   ├── build.gradle.kts           ← java-gradle-plugin
│   ├── src/main/kotlin/education/cccp/hyperframes/
│   │   ├── HyperframesPlugin.kt
│   │   ├── GenerateHyperframesHtmlTask.kt
│   │   ├── RenderHyperframesTask.kt
│   │   └── HyperframesExtension.kt
│   ├── .agents/                   ← gouvernance agent
│   └── doc/
│       └── HYPERFRAMES_ARCHITECTURE.adoc
└── video.yml                      ← configuration dogfood&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_4段階のパイプライン&amp;quot;&amp;gt;4段階のパイプライン&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
skinparam backgroundColor #FEFEFE
skinparam defaultFontSize 11

title パイプライン hyperframes-gradle
rectangle &amp;quot;AsciiDoc
ソース&amp;quot; as adoc #LightYellow
rectangle &amp;quot;AsciidoctorJ&amp;quot; as asciidoctorj #LightBlue
rectangle &amp;quot;HTMLハイパーフレーム\n(data-*属性)&amp;quot; as html #LightGreen
rectangle &amp;quot;HyperFrames CLI
(Node.js 22+)&amp;quot; as cli #Lavender
rectangle &amp;quot;video.mp4&amp;quot; as mp4 #Gold

adoc -right-&amp;amp;gt; asciidoctorj : parse blocs customs
asciidoctorj -right-&amp;amp;gt; html : génère HTML
html -right-&amp;amp;gt; cli : ProcessBuilder\nnpx hyperframes render
cli -right-&amp;amp;gt; mp4 : Puppeteer + FFmpeg
@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;olist arabic&amp;quot;&amp;gt;
&amp;lt;ol class=&amp;quot;arabic&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;AsciidoctorJ&amp;lt;/strong&amp;gt; は AsciiDoc ソースを解析し、カスタム ブロックを抽出します&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ol&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;code&amp;gt;[hyperframes-composition]&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;[hyperframes-track]&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;[hyperframes-animation]&amp;lt;/code&amp;gt;.&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;olist arabic&amp;quot;&amp;gt;
&amp;lt;ol class=&amp;quot;arabic&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;GenerateHyperframesHtmlTask&amp;lt;/strong&amp;gt; は HyperFrames HTML を生成します とともに&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ol&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;`data-*`対応する属性。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;olist arabic&amp;quot;&amp;gt;
&amp;lt;ol class=&amp;quot;arabic&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;*RenderHyperframesTask*はHyperFrames CLIを経由して呼び出す`ProcessBuilder`:&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ol&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;code&amp;gt;npx hyperframes render --input index.html --output video.mp4&amp;lt;/code&amp;gt;。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;olist arabic&amp;quot;&amp;gt;
&amp;lt;ol class=&amp;quot;arabic&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;MP4は展開されます`output/`と`metadata.json`オーケストレーションのために&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ol&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_asciidoc_dsl&amp;quot;&amp;gt;AsciiDoc DSL&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;プラグインの本当の付加価値は、AsciiDoc DSLです。ユーザー 彼は決してHTMLを書きません。彼は既存のAsciiDocドキュメントに注釈を付けます：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-asciidoc hljs&amp;quot; data-lang=&amp;quot;asciidoc&amp;quot;&amp;gt;= Formation Docker &amp;amp;amp; Kubernetes
:hyperframes-width: 1920
:hyperframes-height: 1080
:hyperframes-fps: 30

[hyperframes-composition, id=&amp;quot;intro&amp;quot;]
== Introduction

Le titre apparaît avec un fondu GSAP sur fond vidéo.

[hyperframes-track, index=0, start=0, duration=6]
video::assets/background.mp4[muted, playsinline]

[hyperframes-track, index=1, start=1, duration=4]
Formation Docker &amp;amp;amp; Kubernetes

[hyperframes-animation, type=gsap]&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;const tl = gsap.timeline({ paused: true }); tl.from(&amp;quot;#title&amp;quot;, { opacity: 0, y: 40, duration: 0.8 }, 1); window.&amp;lt;em&amp;gt;timelines = window.&amp;lt;/em&amp;gt;timelines || {}; window.__timelines.intro = tl;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;docinfo属性 (&amp;lt;code&amp;gt;:hyperframes-width:&amp;lt;/code&amp;gt;) ディメンションを設定します。 カスタムブロックは構成とトラックを定義します。ブロック `[hyperframes-animation]`生のGSAPコードを含んでいる — AIエージェントが 自然言語の説明から生成できる。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_node_js_ブリッジ&amp;quot;&amp;gt;Node.js ブリッジ&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;唯一の技術的な摩擦ポイント：HyperFramesはNode.js/TypeScriptで実装されています、 そして私のプラグインはKotlin/JVMで書かれています。解決策は`ProcessBuilder` :&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-kotlin hljs&amp;quot; data-lang=&amp;quot;kotlin&amp;quot;&amp;gt;class RenderHyperframesTask : DefaultTask() {

    @TaskAction
    fun render() {
        val process = ProcessBuilder(
            &amp;quot;npx&amp;quot;, &amp;quot;hyperframes&amp;quot;, &amp;quot;render&amp;quot;,
            &amp;quot;--input&amp;quot;, inputHtml.absolutePath,
            &amp;quot;--output&amp;quot;, outputMp4.absolutePath
        )
            .inheritIO()
            .start()

        val exitCode = process.waitFor()
        require(exitCode == 0) {
            &amp;quot;HyperFrames render failed with exit code $exitCode&amp;quot;
        }
    }
}&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;JVMコードとNode.jsの間の結合はゼロです。契約はコマンドラインで行われます。 およびディスク上のファイル。これは同じパターンです。&amp;lt;code&amp;gt;plantuml-gradle&amp;lt;/code&amp;gt; (PlantUML CLIを呼び出す) または`slider-gradle`（AsciidoctorJを呼び出す）。 太陽の下に新しいものは何もない — ただ新しいツールに適用されているだけだ。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_2つのビデオプラグイン2つの使い方&amp;quot;&amp;gt;2つのビデオプラグイン、2つの使い方&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;table class=&amp;quot;tableblock frame-all grid-all stretch&amp;quot;&amp;gt;
&amp;lt;colgroup&amp;gt;
&amp;lt;col style=&amp;quot;width: 4.7619%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 4.7619%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 4.7619%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 4.7619%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 4.7619%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 4.7619%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 4.7619%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 4.7619%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 4.7619%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 4.7619%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 4.7619%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 4.7619%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 4.7619%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 4.7619%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 4.7619%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 4.7619%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 4.7619%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 4.7619%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 4.7619%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 4.7619%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 4.762%;&amp;quot;&amp;gt;
&amp;lt;/colgroup&amp;gt;
&amp;lt;tbody&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;カプセル-gradle&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;hyperframes-gradle&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;出典&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;Deck reveal.js (既存のHTML)&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;AsciiDoc → HTML HyperFrames&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;ユースケース&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;復習カプセル&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;スタンドアロン説明動画&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;自然&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;スライド → ビデオ&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;ドキュメント → ビデオ&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;レンダリングされた&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;Playwright Java → WebM&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;HyperFrames CLI → MP4&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;アニメーション&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;トランジション reveal.js ネイティブ&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;GSAP/CSSデータ属性&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;スタック&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;100% JVM (Kotlin)&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;JVM + Node.js外部CLI&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/tbody&amp;gt;
&amp;lt;/table&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;彼らは互いに置き換わらない。彼らは互いに補完し合う。完全なバリューチェーン：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;AsciiDoc ──→ slider-gradle ──→ deck reveal.js ──→ capsule-gradle ──→ WebM (復習カプセル)&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;AsciiDoc ──→ hyperframes-gradle ──→ MP4 (ビデオ スタンドアローン)&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;ユーザーは単一のAsciiDocファイルを書きます。slider-gradleはスライドを生成します。 capsule-gradle はレビュー用カプセルを生成します。 hyperframes-gradle は ティーザー映像と技術デモ。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_ロードマップの6つのepic&amp;quot;&amp;gt;ロードマップの6つのEPIC&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;プラグインは6つのEPICに構造化されています：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;table class=&amp;quot;tableblock frame-all grid-all stretch&amp;quot;&amp;gt;
&amp;lt;colgroup&amp;gt;
&amp;lt;col style=&amp;quot;width: 4.1666%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 4.1666%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 4.1666%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 4.1666%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 4.1666%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 4.1666%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 4.1666%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 4.1666%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 4.1666%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 4.1666%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 4.1666%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 4.1666%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 4.1666%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 4.1666%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 4.1666%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 4.1666%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 4.1666%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 4.1666%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 4.1666%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 4.1666%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 4.1666%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 4.1666%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 4.1666%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 4.1682%;&amp;quot;&amp;gt;
&amp;lt;/colgroup&amp;gt;
&amp;lt;tbody&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;エピック&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;説明&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;優先&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;HF-0&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;Bootstrap ガバナンス + アーキテクチャのフレーミング&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;�✅ 終了&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;HF-1&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;Gradle スタブプラグイン + AsciidoctorJ 統合&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;P0&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;HF-2&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;Bridge CLI HyperFrames（ProcessBuilder → npx → MP4）&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;P1&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;HF-3&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;DSL AsciiDoc の慣習 (ブロック、docinfo、テンプレート)&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;P1&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;HF-4&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;ランナー Gradle の統合 (metadata.json)&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;P2&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;HF-5&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;すぐに使えるテンプレート (title-card, code-diff, captions)&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;P3&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;HF-6&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;CI + Maven Central / Gradle Portal への公開&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;P3&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/tbody&amp;gt;
&amp;lt;/table&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;セッション000（bootstrap）は既に完了しました。セッション001はHF-1を攻撃します： Gradle プラグインのスタブと AsciidoctorJ の統合。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_なぜそれが機能するのか&amp;quot;&amp;gt;なぜそれが機能するのか&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;三つの理由：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;olist arabic&amp;quot;&amp;gt;
&amp;lt;ol class=&amp;quot;arabic&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;HyperFramesは&amp;quot;built for agents&amp;quot;&amp;lt;/strong&amp;gt; 私のパイプラインはAIエージェントに基づいています&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ol&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;(planner-gradle + deepseek) コンテンツを生成する. HyperFrames 受け入れる HTMLの素 — LLMが最も得意とするフォーマット。Reactはなく、 JSXについては、エージェントに学習曲線はありません。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;olist arabic&amp;quot;&amp;gt;
&amp;lt;ol class=&amp;quot;arabic&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;*AsciiDoc DSLは自然です。 私のエコシステム全体がAsciiDocを話します。&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ol&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;slider-gradle, codex-gradle, training-gradle — すべてが消費している`.adoc`。 カスタムブロックを追加`[hyperframes-composition]`拡張機能です 論理的で、断絶ではない。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;olist arabic&amp;quot;&amp;gt;
&amp;lt;ol class=&amp;quot;arabic&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;Node.jsブリッジは確立されたパターンです&amp;lt;/strong&amp;gt;. JVM外のProcessBuilder,&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ol&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;これが私がPlantUML、Graphviz、Piperのために既にやっていることです。 HyperFramesを追加 アーキテクチャに何も変更を加えません — 外部ツールがひとつ増えるだけです Gradle から制御されています&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;admonitionblock note&amp;quot;&amp;gt;
&amp;lt;table&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;icon&amp;quot;&amp;gt;
&amp;lt;i class=&amp;quot;fa icon-note&amp;quot; title=&amp;quot;ℹ️&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;
&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;パターンの本当の強みは、&amp;lt;strong&amp;gt;aucune&amp;lt;/strong&amp;gt; npm の依存関係がないということです Gradleビルド。プラグインはNode.jsコードをインポートしません。それは実行します シェルコマンド。HyperFrames が進化または故障した場合、プラグインは結合されません。 — コマンドを更新するだけです。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/table&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_結論_欠けているリンク&amp;quot;&amp;gt;結論 : 欠けているリンク&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;hyperframes-gradleを使って、私のビデオパイプラインは完了です。私は：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;インタラクティブなスライド（slider-gradle）&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;これらの*復習カプセル* (capsule-gradle)&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;スタンドアロン動画&amp;lt;/strong&amp;gt; (hyperframes-gradle)&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;3つのフォーマット。1つのソースファイル：AsciiDoc。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;次の目標はHF-1：プラグインをコンパイルして生成する 注釈が付いたAsciiDocドキュメントからの最初のHTML HyperFrames。 セッション 001はすでに構図が決まっている。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;hyperframes-gradleは存在します。ガバナンスは整っています。バックログ 書かれています。 アーキテクチャは文書化されています。 プラグインが生まれました。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_参考文献&amp;quot;&amp;gt;参考文献&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;0124_architecture_plugin_gradle_racine_consommateur_independant_post.html&amp;quot;&amp;gt;Article 0124 — 独立プラグインアーキテクチャ + コンシューマー ルート&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;https://github.com/heygen-com/hyperframes&amp;quot;&amp;gt;ハイパーフレーム — GitHub&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;https://hyperframes.heygen.com/introduction&amp;quot;&amp;gt;HyperFrames — ドキュメンテーション&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;code&amp;gt;foundry/public/hyperframes-gradle/hyperframes-plugin/doc/HYPERFRAMES_ARCHITECTURE.adoc&amp;lt;/code&amp;gt;— 詳細なアーキテクチャ&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;</description>
        </item><item>
            <title>私のLLM消費の監査：SQLite、OpenCode、Ollama Cloud、そしてなぜ私のプロサブスクリプションが世界市場を破壊するのか</title>
            <link >https://cheroliv.com/blog/2026/0125_audit_conso_opencode_methodologie_comparaison_prix_llm_post.html</link>
            <pubDate>Mon, 18 May 2026 00:00:00 +0000</pubDate>
            <guid isPermaLink="false">blog/2026/0125_audit_conso_opencode_methodologie_comparaison_prix_llm_post.html</guid>
            <description>&amp;lt;div id=&amp;quot;toc&amp;quot; class=&amp;quot;toc&amp;quot;&amp;gt;
&amp;lt;div id=&amp;quot;toctitle&amp;quot;&amp;gt;Table des matières&amp;lt;/div&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel1&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_スタックを理解する誰が何をやるのか&amp;quot;&amp;gt;スタックを理解する：誰が何をやるのか？&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_導入なぜ監査が必要ですか&amp;quot;&amp;gt;導入：なぜ監査が必要ですか？&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_opencodeデータベース_金脈&amp;quot;&amp;gt;OpenCodeデータベース : 金脈&amp;lt;/a&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel2&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_スキーマ&amp;quot;&amp;gt;スキーマ&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_抽出コード&amp;quot;&amp;gt;抽出コード&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_結果_73日分の消費&amp;quot;&amp;gt;結果 : 73日分の消費&amp;lt;/a&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel2&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_全体像&amp;quot;&amp;gt;全体像&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_モデルおよびサプライヤーによる換気&amp;quot;&amp;gt;モデルおよびサプライヤーによる換気&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_イントラセッション_モデル_セッション_テーブルが見ないもの&amp;quot;&amp;gt;イントラセッション モデル ： セッション テーブルが見ないもの&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_料金比較_西洋のサプライヤー&amp;quot;&amp;gt;料金比較 — 西洋のサプライヤー&amp;lt;/a&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel2&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_anthropic_claude&amp;quot;&amp;gt;Anthropic — Claude&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_openai_gpt&amp;quot;&amp;gt;OpenAI — GPT&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_グーグル_ジェミニ&amp;quot;&amp;gt;グーグル — ジェミニ&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_huggingface_推論プロバイダー&amp;quot;&amp;gt;HuggingFace 推論プロバイダー&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_グロク&amp;quot;&amp;gt;グロク&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_料金比較_中国のサプライヤー&amp;quot;&amp;gt;料金比較 — 中国のサプライヤー&amp;lt;/a&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel2&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_deepseek_api_direct_platform_deepseek_com&amp;quot;&amp;gt;DeepSeek API Direct (platform.deepseek.com)&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_kimi_ムーンショット_platform_kimi_com&amp;quot;&amp;gt;Kimi ムーンショット (platform.kimi.com)&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_alibaba_bailian_bailian_aliyun_com&amp;quot;&amp;gt;Alibaba Bailian (bailian.aliyun.com)&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_サマリー表_すべてのプロバイダー&amp;quot;&amp;gt;サマリー表 — すべてのプロバイダー&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_隠れたコストプロンプトエンジニアリングとイテレーション&amp;quot;&amp;gt;�隠れたコスト：プロンプトエンジニアリングとイテレーション&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_ollama_cloud_proのサブスクリプションを累積するdockerメソッド&amp;quot;&amp;gt;Ollama Cloud Proのサブスクリプションを累積する：Dockerメソッド&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_監査が測らないもの&amp;quot;&amp;gt;監査が測らないもの&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_結論数字の裁定&amp;quot;&amp;gt;結論：数字の裁定&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_参考文献&amp;quot;&amp;gt;参考文献&amp;lt;/a&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel2&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_料金の出所&amp;quot;&amp;gt;料金の出所&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div id=&amp;quot;preamble&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;読了時間 : 22 minutes&amp;lt;/div&amp;gt;
&amp;lt;p&amp;gt;私はいつも AI の消費コストがいくらかと聞かれます。私は「月20ユーロ」と答えると、目を丸くして見られます。それでは今日、私はブラックボックスを開けます。この記事は、私の73日間のvibe codingの完全な監査です：OpenCodeのSQLiteデータベースからデータを抽出する方法論、テーブルをクエリするSQLコード、そして市場のすべてのプロバイダー――西洋のものも中国のものも――との包括的な比較。その結果は極めて非対称で、私は計算を3回確認しなければなりませんでした。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;dlist&amp;quot;&amp;gt;
&amp;lt;dl&amp;gt;
&amp;lt;dt class=&amp;quot;hdlist1&amp;quot;&amp;gt;トク&amp;lt;/dt&amp;gt;
&amp;lt;dd&amp;gt;
&amp;lt;p&amp;gt;[]&amp;lt;/p&amp;gt;
&amp;lt;/dd&amp;gt;
&amp;lt;/dl&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_スタックを理解する誰が何をやるのか&amp;quot;&amp;gt;スタックを理解する：誰が何をやるのか？&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;数字に飛び込む前に、アーキテクチャを明確にしましょう。私のセットアップには3つの異なるアクターが存在し、これを混同しないようにすることが重要です：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
skinparam backgroundColor #FEFEFE
skinparam defaultFontSize 12

title 私のLLMスタックの3つのアクター
left to right direction

actor &amp;quot;私 (開発者)&amp;quot; as Dev

package &amp;quot;オープンコード
(github.com/anomalyco/opencode)&amp;quot; as OC {
  rectangle &amp;quot;Vibe codingのCLI
オープンソース、無料&amp;quot; as CLI
  note right of CLI
    C&amp;#39;est l&amp;#39;outil que j&amp;#39;utilise
    pour coder avec des agents IA.
    Il ne fournit AUCUN modèle.
    C&amp;#39;est un terminal + un orchestrateur.
  end note
}

package &amp;quot;Ollama (ローカルインストール)&amp;quot; as OL {
  rectangle &amp;quot;推論クライアント
私のマシンにインストール済み&amp;quot; as Client
  note right of Client
    C&amp;#39;est le logiciel qui fait tourner
    les modèles. Il peut les exécuter
    en local OU les déléguer au cloud
    selon le tag (:cloud).
    Il s&amp;#39;authentifie via clé SSH.
  end note
}

package &amp;quot;Ollama クラウド
(ollama.com)&amp;quot; as OCloud {
  rectangle &amp;quot;クラウド推論サービス
プロサブスクリプション : 20ユーロ/月&amp;quot; as Cloud
  note right of Cloud
    C&amp;#39;est le fournisseur d&amp;#39;inférence.
    Mes modèles avec le tag :cloud
    sont exécutés sur LEURS serveurs.
    L&amp;#39;abonnement Pro donne accès
    à des quotas supérieurs.
  end note
}

Dev --&amp;amp;gt; CLI : &amp;quot;プロンプトを打ち込む&amp;quot;
CLI --&amp;amp;gt; Client : &amp;quot;このモデルを呼び出せ&amp;quot;
Client --&amp;amp;gt; Cloud : &amp;quot;SSHキー + リクエスト\n(モデル :クラウド)&amp;quot;
Client --&amp;amp;gt; Client : &amp;quot;ローカル実行
(:cloud を使わないモデル)&amp;quot;

@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;admonitionblock important&amp;quot;&amp;gt;
&amp;lt;table&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;icon&amp;quot;&amp;gt;
&amp;lt;i class=&amp;quot;fa icon-important&amp;quot; title=&amp;quot;❗&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;
&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;オープンコードはモデル提供者ではありません。&amp;lt;/strong&amp;gt;これはオープンソースのCLIです (&amp;lt;a href=&amp;quot;https://github.com/anomalyco/opencode&amp;quot;&amp;gt;github.com/anomalyco/opencode&amp;lt;/a&amp;gt;) は AI エージェントをオーケストレーションし、サブスクリプションを販売せず、推論も提供せず、これが～に相当します。&amp;lt;code&amp;gt;git`バージョン管理のために : ツールであって、サービスではない。 &amp;lt;strong&amp;gt;Ollama Cloud は推論のプロバイダー。&amp;lt;/strong&amp;gt;私のローカルのOllamaインストールは &amp;lt;strong&amp;gt;client&amp;lt;/strong&amp;gt; として機能し — Ollamaのサーバーに一意のSSHキー（Device Key）で認証し、タグ付けされたモデルの実行をそれらに委任します。&amp;lt;/code&amp;gt;:cloud`. Proサブスクリプション（月20€）は、より高いクォータを解放し、Dockerを使って同じマシンで複数のアカウントを併用できるようになります。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/table&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_導入なぜ監査が必要ですか&amp;quot;&amp;gt;導入：なぜ監査が必要ですか？&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;2か月前、私はローカルのOllamaインストールでモデルを無料で使用していました。 その後、月額20ユーロのOllama Cloud Proの最初のサブスクリプションに登録し、これによりクラウドモデル（タグが付いているもの`:cloud`) プロバイダー経由`ollama-cloud`. 2か月後に別のDockerインスタンスで独自のアカウントとSSHキーを使って2番目のサブスクリプションが追加されました — この積み上げ方法は &amp;lt;a href=&amp;quot;0120_cumuler_deux_abonnements_ollama_pro_docker_post.html&amp;quot;&amp;gt;mon article sur le cumul d&amp;amp;#8217;abonnements&amp;lt;/a&amp;gt; で説明されています。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;私を悩ませていた質問：&amp;lt;strong&amp;gt;これらの20ユーロ／月は正当化されるのか？&amp;lt;/strong&amp;gt; 思い付きではなく。数字で。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;回答するために、私は正確なデータが必要でした。見積もりでもなく、平均でもなく。私の*実際の*消費量、トークンごと、モデルごと、セッションごと。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;そして OpenCode — CLI — すべてを SQLite データベースに保存します。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_opencodeデータベース_金脈&amp;quot;&amp;gt;OpenCodeデータベース : 金脈&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;OpenCode はすべてのセッション履歴を指定された場所にある SQLite ファイルに保持します`~/.local/share/opencode/opencode.db`. La mienne pèse 660 Mo pour 73 jours d&amp;amp;#8217;utilisation — une base de données de production tout à fait respectable.&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;$ ls -lh ~/.local/share/opencode/opencode.db
-rw-r--r-- 1 cheroliv cheroliv 660M mai 18 12:25 opencode.db&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_スキーマ&amp;quot;&amp;gt;スキーマ&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;データベースには約20のテーブルがありますが、うち3つは監査にとって重要です：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
skinparam backgroundColor #FEFEFE
skinparam defaultFontSize 12

title 簡略化されたスキーマ — OpenCode SQLite
entity &amp;quot;セッション&amp;quot; as S {
  * id : TEXT
  --
  * model : TEXT (JSON)
  * cost : REAL
  * tokens_input : INTEGER
  * tokens_output : INTEGER
  * tokens_reasoning : INTEGER
  * tokens_cache_read : INTEGER
  * tokens_cache_write : INTEGER
  * time_created : INTEGER
  * project_id : TEXT
}

entity &amp;quot;メッセージ&amp;quot; as M {
  * id : TEXT
  --
  * session_id : TEXT &amp;amp;lt;&amp;amp;lt;FK&amp;amp;gt;&amp;amp;gt;
  * data : TEXT (JSON)
  * time_created : INTEGER
}

entity &amp;quot;プロジェクト&amp;quot; as P {
  * id : TEXT
  --
  * worktree : TEXT
  * name : TEXT
}

S ||--o{ M : &amp;quot;セッションID&amp;quot;
S }o--|| P : &amp;quot;project_id&amp;quot;

note right of S
  La table session agrège
  tokens + coût + modèle.
  C&amp;#39;est notre point d&amp;#39;entrée
  principal.
end note

note right of M
  Les messages individuels.
  Le champ data contient
  le modèle utilisé (format JSON)
  même si la session change
  de modèle en cours de route.
end note

@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;テーブル`session`これはグローバルな監査に最適です：各セッションには集約されたトークン数、使用されたモデル、およびコストがあります。フィールド`model`生のJSONです :&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-json hljs&amp;quot; data-lang=&amp;quot;json&amp;quot;&amp;gt;{
  &amp;quot;id&amp;quot;: &amp;quot;deepseek-v4-pro:cloud&amp;quot;,
  &amp;quot;providerID&amp;quot;: &amp;quot;ollama-cloud&amp;quot;,
  &amp;quot;variant&amp;quot;: &amp;quot;default&amp;quot;
}&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;admonitionblock important&amp;quot;&amp;gt;
&amp;lt;table&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;icon&amp;quot;&amp;gt;
&amp;lt;i class=&amp;quot;fa icon-important&amp;quot; title=&amp;quot;❗&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;
&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;フィールド`cost`OpenCode データベースでは、&amp;lt;strong&amp;gt;外部 API 料金&amp;lt;/strong&amp;gt;（API キー経由での従量課金、Google Gemini、OpenAI など）のみが反映されます。 Ollama を経由した呼び出し — ローカルでも Ollama Cloud Pro でも — はマークされます。`cost=0`理由は、コストが定額（サブスクリプション）で、トークンあたりではないからです。これらの呼び出しの本当のコストは、月額サブスクリプションです。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/table&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_抽出コード&amp;quot;&amp;gt;抽出コード&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;何もインストールする必要はありません。Node.js 22+ は実験的な SQLiteモジュールを組み込んでいます (&amp;lt;code&amp;gt;node:sqlite&amp;lt;/code&amp;gt;) 完璧に機能しています。これが私がすべてを与えてくれたスクリプト：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-javascript hljs&amp;quot; data-lang=&amp;quot;javascript&amp;quot;&amp;gt;const { DatabaseSync } = require(&amp;#39;node:sqlite&amp;#39;);
const db = new DatabaseSync(
  `${process.env.HOME}/.local/share/opencode/opencode.db`,
  { readonly: true }
);

// 1. Statistiques globales
const global = db.prepare(`
  SELECT
    COUNT(*) as sessions,
    SUM(tokens_input) as total_input,
    SUM(tokens_output) as total_output,
    SUM(tokens_reasoning) as total_reasoning,
    SUM(tokens_cache_read) as total_cache_read,
    SUM(cost) as total_cost
  FROM session
`).get();

// 2. Ventilation par modèle et fournisseur
const byModel = db.prepare(`
  SELECT
    json_extract(model, &amp;#39;$.id&amp;#39;) as model_id,
    json_extract(model, &amp;#39;$.providerID&amp;#39;) as provider,
    COUNT(*) as sessions,
    SUM(tokens_input) as total_input,
    SUM(tokens_output) as total_output,
    SUM(cost) as total_cost
  FROM session
  WHERE model IS NOT NULL
  GROUP BY model_id, provider
  ORDER BY SUM(tokens_input) DESC
`).all();

// 3. Par mois
const monthly = db.prepare(`
  SELECT
    strftime(&amp;#39;%Y-%m&amp;#39;, datetime(time_created/1000, &amp;#39;unixepoch&amp;#39;)) as month,
    COUNT(*) as sessions,
    SUM(tokens_input) as total_input,
    SUM(tokens_output) as total_output,
    SUM(cost) as total_cost
  FROM session
  WHERE time_created IS NOT NULL
  GROUP BY month
  ORDER BY month
`).all();

// 4. Messages par modèle (détection des changements intra-session)
const msgByModel = db.prepare(`
  SELECT
    json_extract(m.data, &amp;#39;$.model.providerID&amp;#39;) as provider,
    json_extract(m.data, &amp;#39;$.model.modelID&amp;#39;) as model_id,
    COUNT(*) as messages
  FROM message m
  WHERE json_extract(m.data, &amp;#39;$.model&amp;#39;) IS NOT NULL
  GROUP BY provider, model_id
  ORDER BY COUNT(*) DESC
`).all();

console.log({ global, byModel, monthly, msgByModel });
db.close();&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;admonitionblock note&amp;quot;&amp;gt;
&amp;lt;table&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;icon&amp;quot;&amp;gt;
&amp;lt;i class=&amp;quot;fa icon-note&amp;quot; title=&amp;quot;ℹ️&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;
&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;フラグ`--experimental-sqlite`� 必要です Node.js 22.x。 Node.js 24+ では、モジュールは安定しており、フラグは必要なくなりました。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/table&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_結果_73日分の消費&amp;quot;&amp;gt;結果 : 73日分の消費&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_全体像&amp;quot;&amp;gt;全体像&amp;lt;/h3&amp;gt;
&amp;lt;table class=&amp;quot;tableblock frame-all grid-all stretch&amp;quot;&amp;gt;
&amp;lt;colgroup&amp;gt;
&amp;lt;col style=&amp;quot;width: 33.3333%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 33.3333%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 33.3334%;&amp;quot;&amp;gt;
&amp;lt;/colgroup&amp;gt;
&amp;lt;thead&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;th class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;メトリック&amp;lt;/th&amp;gt;
&amp;lt;th class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;�値&amp;lt;/th&amp;gt;
&amp;lt;th class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;コンテキスト&amp;lt;/th&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/thead&amp;gt;
&amp;lt;tbody&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;OpenCode セッション&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;1 022&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;平均で約14セッション/日&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;トークン入力&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;2.62億&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;そのうち94,5Mのキャッシュヒット&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;トークン出力&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;2100万&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;Ratio input/output ~125:1&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;トークンの推論&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;141 000&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;微々たる — ほとんど考えない&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;外部 API コスト&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;$0.22&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;サブスクリプション外の手数料 (Gemini + 無料プラン)&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/tbody&amp;gt;
&amp;lt;/table&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;この数字の \$0,22 は重要です：それは私が Ollama Cloud Pro のサブスクリプションに加えて支払ったすべてを表しています。つまりほぼゼロです。サブスクリプションは基本をカバーしています。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
skinparam backgroundColor #FEFEFE
skinparam defaultFontSize 12

title 月次進化 — トークン入力
rectangle &amp;quot;2026年3月
9セッション
37.7Mトークン&amp;quot; as MARS #FFE082
rectangle &amp;quot;2026年4月
486セッション
13.3億トークン&amp;quot; as AVR #81C784
rectangle &amp;quot;2026年5月
527セッション
12.5億トークン&amp;quot; as MAI #64B5F6

MARS -right-&amp;amp;gt; AVR : ×35
AVR -right-&amp;amp;gt; MAI : stable (période en cours)

note bottom of MAI
  Mai comptabilisé jusqu&amp;#39;au 18.
  Projection mois complet : ~2,1 Md tokens
  si la tendance se maintient.
end note
@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;3月と4月の打ち上げは目を見張るもので：1か月で×35に増加しました。これは「テスト」使用から「本番」使用への移行であり、GradleプラグインのためにOpenCodeエージェントを継続的に動かし始めたときだ。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_モデルおよびサプライヤーによる換気&amp;quot;&amp;gt;モデルおよびサプライヤーによる換気&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;フィールド`model`テーブルの`session`JSONである,`json_extract()`きれいに換気できる :&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;table class=&amp;quot;tableblock frame-all grid-all stretch&amp;quot;&amp;gt;
&amp;lt;colgroup&amp;gt;
&amp;lt;col style=&amp;quot;width: 27.2727%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 18.1818%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 18.1818%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 18.1818%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 18.1819%;&amp;quot;&amp;gt;
&amp;lt;/colgroup&amp;gt;
&amp;lt;thead&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;th class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;モデル × プロバイダー&amp;lt;/th&amp;gt;
&amp;lt;th class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;セッション&amp;lt;/th&amp;gt;
&amp;lt;th class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;(Empty)&amp;lt;/th&amp;gt;
&amp;lt;th class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;Output&amp;lt;/th&amp;gt;
&amp;lt;th class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;コスト&amp;lt;/th&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/thead&amp;gt;
&amp;lt;tbody&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;deepseek-v4-pro @ ollama-cloud&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;63&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;220 M&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;1,94 M&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;\$0&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;deepseek-v4-pro @ ollama-b&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;124&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;463 M&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;4,15 M&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;\$0&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;deepseek-v4-pro @ ollama&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;100&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;252 M&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;2,25 M&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;\$0&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;deepseek-v4-flash-free @ opencode&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;16&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;1,3 M&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;279 K&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;\$0&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;qwen3.6-plus-free @ opencode&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;1&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;369 K&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;25 K&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;\$0&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;gemini-2.5-flash @ google&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;1&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;211 K&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;19 K&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;\$0,04&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/tbody&amp;gt;
&amp;lt;/table&amp;gt;
&amp;lt;div class=&amp;quot;admonitionblock important&amp;quot;&amp;gt;
&amp;lt;table&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;icon&amp;quot;&amp;gt;
&amp;lt;i class=&amp;quot;fa icon-important&amp;quot; title=&amp;quot;❗&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;
&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;まさに同じDeepSeek V4 Proモデルのための3つの異なるプロバイダー：
* &amp;lt;code&amp;gt;ollama-cloud&amp;lt;/code&amp;gt;→ 経由 &amp;lt;strong&amp;gt;有料Proサブスクリプション&amp;lt;/strong&amp;gt; (Ollama管理のクラウド)
* &amp;lt;code&amp;gt;ollama-b&amp;lt;/code&amp;gt;→ &amp;lt;strong&amp;gt;２番目のProサブスクリプション&amp;lt;/strong&amp;gt;, 別のDockerコンテナ内で隔離されている
* &amp;lt;code&amp;gt;ollama&amp;lt;/code&amp;gt;→ ネイティブロケールのインスタンス, &amp;lt;strong&amp;gt;無料&amp;lt;/strong&amp;gt; (私のマシンで直接動作する)
3つの合計は 936M 入力、8.4M 出力 — これが私の DeepSeek V4 Pro の総消費量で、すべてのプロバイダーを合わせたものです。ただ`ollama-cloud`(220M input)は有料です（サブスクリプション）。 残りの716Mは無料です（ローカルまたはサブスクリプションの累積）。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/table&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_イントラセッション_モデル_セッション_テーブルが見ないもの&amp;quot;&amp;gt;イントラセッション モデル ： セッション テーブルが見ないもの&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;テーブル`session`セッションの &amp;lt;strong&amp;gt;主要&amp;lt;/strong&amp;gt; モデルしかキャプチャしない。しかし、同じセッション中でも、OpenCode エージェントは複数のモデル間を切り替えることができます。テーブル`message`明らかにする：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-text hljs&amp;quot; data-lang=&amp;quot;text&amp;quot;&amp;gt;Modèles utilisés dans les messages (ollama-cloud provider) :
├─ deepseek-v4-pro      1 441 msgs  (32%)
├─ qwen3.5:397b         1 217 msgs  (27%)
├─ glm-5.1                712 msgs  (16%)
├─ kimi-k2.6:cloud        634 msgs  (14%)
├─ qwen3-coder:480b       414 msgs   (9%)
├─ gpt-oss:20b             34 msgs  (0,8%)
├─ qwen3-coder-next        27 msgs  (0,6%)
└─ gemma4:31b               7 msgs  (0,2%)&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;admonitionblock caution&amp;quot;&amp;gt;
&amp;lt;table&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;icon&amp;quot;&amp;gt;
&amp;lt;i class=&amp;quot;fa icon-caution&amp;quot; title=&amp;quot;🔒&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;
&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;もう Qwen、GLM、Kimi とその他のモデルは使わなくなりました。これは私が4月にさまざまなことをテストしたため、履歴に表示されます。5月中旬から、私は DeepSeek V4 Pro にロックされています — これが長いコンテキストでもエージェントガバナンスとともに負荷に耐える唯一のモデルです。(参照 &amp;lt;code&amp;gt;&amp;lt;a href=&amp;quot;0112_comparaison_kimi_glm_deepseek_long_contexte_plugin_gradle_opencode_post.html&amp;quot;&amp;gt;ma comparaison Kimi/GLM/DeepSeek&amp;lt;/a&amp;gt;&amp;lt;/code&amp;gt;) 履歴における DeepSeek メッセージの 32% は誤解を招きます：今日は 100% です。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/table&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_料金比較_西洋のサプライヤー&amp;quot;&amp;gt;料金比較 — 西洋のサプライヤー&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;問題となる質問：この同じ消費量が伝統的な供給業者ではいくらになるでしょうか？&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;比較のための私の計算基準：&amp;lt;strong&amp;gt;220Mトークン入力 + 1.9Mトークン出力&amp;lt;/strong&amp;gt;— &amp;lt;strong&amp;gt;のみ&amp;lt;/strong&amp;gt; 体積を通過した`ollama-cloud`(私の有料サブスクリプションに対応する唯一のもの). 残りの716Mは無料です (Ollama ローカルおよび Docker B インスタンス).&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;table class=&amp;quot;tableblock frame-all grid-all stretch&amp;quot;&amp;gt;
&amp;lt;colgroup&amp;gt;
&amp;lt;col style=&amp;quot;width: 23.0769%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 15.3846%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 15.3846%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 15.3846%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 15.3846%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 15.3847%;&amp;quot;&amp;gt;
&amp;lt;/colgroup&amp;gt;
&amp;lt;thead&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;th class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;サプライヤー&amp;lt;/th&amp;gt;
&amp;lt;th class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;モデル&amp;lt;/th&amp;gt;
&amp;lt;th class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;$/M&amp;lt;/th&amp;gt;
&amp;lt;th class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;出力 \$/M&amp;lt;/th&amp;gt;
&amp;lt;th class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;月額コスト&amp;lt;/th&amp;gt;
&amp;lt;th class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;私のサブスクリプション&amp;lt;/th&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/thead&amp;gt;
&amp;lt;tbody&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;私のセットアップ&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;ディープシーク V4 Pro&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;0&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;0&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;\~20€&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;1×&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/tbody&amp;gt;
&amp;lt;/table&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_anthropic_claude&amp;quot;&amp;gt;Anthropic — Claude&amp;lt;/h3&amp;gt;
&amp;lt;table class=&amp;quot;tableblock frame-all grid-all stretch&amp;quot;&amp;gt;
&amp;lt;colgroup&amp;gt;
&amp;lt;col style=&amp;quot;width: 27.2727%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 18.1818%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 18.1818%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 18.1818%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 18.1819%;&amp;quot;&amp;gt;
&amp;lt;/colgroup&amp;gt;
&amp;lt;thead&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;th class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;モデル&amp;lt;/th&amp;gt;
&amp;lt;th class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;\$/M&amp;lt;/th&amp;gt;
&amp;lt;th class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;$/M&amp;lt;/th&amp;gt;
&amp;lt;th class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;月額コスト&amp;lt;/th&amp;gt;
&amp;lt;th class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;× 私のサブスクリプション&amp;lt;/th&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/thead&amp;gt;
&amp;lt;tbody&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;作品4.7&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;\$5&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;\$25&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;\$1 148&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;57×&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;ソネット 4.6&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;\$3&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;\$15&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;\$689&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;34×&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;ハイク 4.5&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;\$1&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;\$5&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;\$230&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;11×&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/tbody&amp;gt;
&amp;lt;/table&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;「最も「経済的」な Claude のモデルである Haiku 4.5 でも、私のサブスクリプションの 11 倍のコストがかかります。さらに、私のコードベースについては何も知らず、私のスタイルでコードを生成せず、Gradle Kotlin DSL の API について幻覚を起こします。」&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_openai_gpt&amp;quot;&amp;gt;OpenAI — GPT&amp;lt;/h3&amp;gt;
&amp;lt;table class=&amp;quot;tableblock frame-all grid-all stretch&amp;quot;&amp;gt;
&amp;lt;colgroup&amp;gt;
&amp;lt;col style=&amp;quot;width: 27.2727%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 18.1818%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 18.1818%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 18.1818%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 18.1819%;&amp;quot;&amp;gt;
&amp;lt;/colgroup&amp;gt;
&amp;lt;thead&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;th class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;モデル&amp;lt;/th&amp;gt;
&amp;lt;th class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;$/M&amp;lt;/th&amp;gt;
&amp;lt;th class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;出力 \$/M&amp;lt;/th&amp;gt;
&amp;lt;th class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;コスト/月&amp;lt;/th&amp;gt;
&amp;lt;th class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;私のサブスクリプション&amp;lt;/th&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/thead&amp;gt;
&amp;lt;tbody&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;GPT 5.5&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;\$5&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;\$30&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;\$1 157&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;58倍&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;GPT 5.4&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;\$2,50&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;\$15&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;\$579&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;29倍&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;GPT 5.4 ミニ&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;\$0,75&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;\$4,50&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;\$174&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;9×&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/tbody&amp;gt;
&amp;lt;/table&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_グーグル_ジェミニ&amp;quot;&amp;gt;グーグル — ジェミニ&amp;lt;/h3&amp;gt;
&amp;lt;table class=&amp;quot;tableblock frame-all grid-all stretch&amp;quot;&amp;gt;
&amp;lt;colgroup&amp;gt;
&amp;lt;col style=&amp;quot;width: 27.2727%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 18.1818%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 18.1818%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 18.1818%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 18.1819%;&amp;quot;&amp;gt;
&amp;lt;/colgroup&amp;gt;
&amp;lt;thead&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;th class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;モデル&amp;lt;/th&amp;gt;
&amp;lt;th class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;$/M&amp;lt;/th&amp;gt;
&amp;lt;th class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;出力 \$/M&amp;lt;/th&amp;gt;
&amp;lt;th class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;月額コスト&amp;lt;/th&amp;gt;
&amp;lt;th class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;×私のサブスクリプション&amp;lt;/th&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/thead&amp;gt;
&amp;lt;tbody&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;ジェミニ 3.1 Pro&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;\$2,00&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;\$10&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;\$459&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;23×&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;ジェミニ3 フラッシュ&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;\$0,30&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;\$1,50&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;\$69&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;3.5倍&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/tbody&amp;gt;
&amp;lt;/table&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;Gemini 3 Flash 69ユーロは、純粋な価格において唯一の「近い」競合です — しかし、これは軽量な密集モデルであり、DeepSeek V4 Proのような1.6T MoEではありません。生成されたコードの品質は比べ物になりません。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_huggingface_推論プロバイダー&amp;quot;&amp;gt;HuggingFace 推論プロバイダー&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;HuggingFace は自ら推論を行わず — サードパーティの &amp;lt;strong&amp;gt;providers&amp;lt;/strong&amp;gt; (Novita, Together, DeepInfra, Cerebras, SambaNova, Fireworks, Groq…) を統一 API を介して集約します。最も安いまたは最も速い provider を選択します。以下は 2026年5月に収集した DeepSeek V4 Pro の料金です：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;table class=&amp;quot;tableblock frame-all grid-all stretch&amp;quot;&amp;gt;
&amp;lt;colgroup&amp;gt;
&amp;lt;col style=&amp;quot;width: 27.2727%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 18.1818%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 18.1818%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 18.1818%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 18.1819%;&amp;quot;&amp;gt;
&amp;lt;/colgroup&amp;gt;
&amp;lt;thead&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;th class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;プロバイダー HF&amp;lt;/th&amp;gt;
&amp;lt;th class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;ドル/メートル&amp;lt;/th&amp;gt;
&amp;lt;th class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;ドル/メートル&amp;lt;/th&amp;gt;
&amp;lt;th class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;コスト/月&amp;lt;/th&amp;gt;
&amp;lt;th class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;× 私のサブスクリプション&amp;lt;/th&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/thead&amp;gt;
&amp;lt;tbody&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;Novita (最も安い)&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;\$1,67&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;\$3,38&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;\$374&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;19倍&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;ディープインフラ&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;\$1,74&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;\$3,48&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;$389&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;19倍&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;一緒に&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;\$2,10&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;\$4,40&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;$470&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;23倍&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;花火&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;非公開料金&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;—&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;—&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;—&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/tbody&amp;gt;
&amp;lt;/table&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;HuggingFace 上でも最も安いプロバイダー (Novita) でさえ、私のサブスクリプション料金の 19 倍を請求します。それに対して Ollama Cloud とは異なり、HF PRO サブスクリプション ($9/月) を持っていない場合、HuggingFace はプラットフォーム手数料も &amp;lt;strong&amp;gt;さらに&amp;lt;/strong&amp;gt; 請求します。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_グロク&amp;quot;&amp;gt;グロク&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;Groq は &amp;lt;strong&amp;gt;aucun&amp;lt;/strong&amp;gt; のモデルを使っていません — 彼らのカタログは GPT-OSS、Llama、Qwen 32B に限られています。比較することは不可能です。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_料金比較_中国のサプライヤー&amp;quot;&amp;gt;料金比較 — 中国のサプライヤー&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;本当のテストは中国市場です。DeepSeekが中国のモデルなら、そのネイティブAPIはもっと安いはずでしょうか？&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_deepseek_api_direct_platform_deepseek_com&amp;quot;&amp;gt;DeepSeek API Direct (platform.deepseek.com)&amp;lt;/h3&amp;gt;
&amp;lt;table class=&amp;quot;tableblock frame-all grid-all stretch&amp;quot;&amp;gt;
&amp;lt;colgroup&amp;gt;
&amp;lt;col style=&amp;quot;width: 33.3333%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 22.2222%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 22.2222%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 22.2223%;&amp;quot;&amp;gt;
&amp;lt;/colgroup&amp;gt;
&amp;lt;thead&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;th class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;期間&amp;lt;/th&amp;gt;
&amp;lt;th class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;$/M&amp;lt;/th&amp;gt;
&amp;lt;th class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;出力 \$/M&amp;lt;/th&amp;gt;
&amp;lt;th class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;月額コスト&amp;lt;/th&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/thead&amp;gt;
&amp;lt;tbody&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;プロモーション -75% (5月31日まで)&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;\$0,435&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;\$0,87&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;98ドル&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;通常運賃 (6月より)&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;\$1,74&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;\$3,48&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;$390&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/tbody&amp;gt;
&amp;lt;/table&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;たとえ DeepSeek の積極的なプロモーション（-75% 延長）でも、直接 API のコストは&amp;lt;strong&amp;gt;5×&amp;lt;/strong&amp;gt;もっと高くなります。 通常料金では,&amp;lt;strong&amp;gt;20×&amp;lt;/strong&amp;gt;. これはDeepSeekのみ — 他のモデルへのアクセスはありません。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_kimi_ムーンショット_platform_kimi_com&amp;quot;&amp;gt;Kimi ムーンショット (platform.kimi.com)&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;Kimiは自社のモデルのみを提案します。DeepSeekはありません。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_alibaba_bailian_bailian_aliyun_com&amp;quot;&amp;gt;Alibaba Bailian (bailian.aliyun.com)&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;中国のすべてのモデルを集約する唯一のプロバイダー — ただし、転売によるマージンを含みます。価格はJavaScriptで動的に読み込まれ、スクレイピングが不可能になります。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_サマリー表_すべてのプロバイダー&amp;quot;&amp;gt;サマリー表 — すべてのプロバイダー&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;table class=&amp;quot;tableblock frame-all grid-all stretch&amp;quot;&amp;gt;
&amp;lt;colgroup&amp;gt;
&amp;lt;col style=&amp;quot;width: 23.0769%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 15.3846%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 15.3846%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 15.3846%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 15.3846%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 15.3847%;&amp;quot;&amp;gt;
&amp;lt;/colgroup&amp;gt;
&amp;lt;thead&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;th class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;供給者&amp;lt;/th&amp;gt;
&amp;lt;th class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;モデル&amp;lt;/th&amp;gt;
&amp;lt;th class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;$/M&amp;lt;/th&amp;gt;
&amp;lt;th class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;出力 \$/M&amp;lt;/th&amp;gt;
&amp;lt;th class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;コスト/月&amp;lt;/th&amp;gt;
&amp;lt;th class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;× 私のサブスクリプション&amp;lt;/th&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/thead&amp;gt;
&amp;lt;tbody&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;オラマ クラウド プロ&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;DeepSeek V4 Pro&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;0&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;0&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;約20ユーロ&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;1×&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;Gemini 3 フラッシュ&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;ジェミニ3フラッシュ&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;\$0,30&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;\$1,50&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;\$69&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;3,5×&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;DeepSeek API (プロモ)&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;ディープシークV4プロ&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;\$0,44&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;\$0,87&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;\$98&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;5×&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;GPT 5.4 Mini&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;GPT 5.4 ミニ&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;\$0,75&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;\$4,50&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;\$174&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;9×&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;Claude Haiku 4.5&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;クロード ハイク 4.5&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;\$1&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;\$5&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;\$230&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;11×&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;HuggingFace/Novita&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;ディープシーク V4 プロ&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;\$1,67&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;\$3,38&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;\$374&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;19×&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;DeepSeek API (通常)&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;DeepSeek V4 Pro&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;\$1,74&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;\$3,48&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;\$390&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;20×&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;Together AI&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;DeepSeek V4 Pro&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;\$2,10&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;\$4,40&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;\$470&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;23×&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;GPT 5.4&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;GPT 5.4&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;\$2,50&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;\$15&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;\$579&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;29×&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;クロード ソネット 4.6&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;Claude Sonnet 4.6&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;\$3&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;\$15&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;\$689&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;34×&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;Claude Opus 4.7&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;Claude Opus 4.7&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;\$5&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;\$25&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;\$1 148&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;57×&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;GPT 5.5&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;GPT 5.5&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;\$5&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;\$30&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;\$1 157&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;58×&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/tbody&amp;gt;
&amp;lt;/table&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
skinparam backgroundColor #FEFEFE
skinparam defaultFontSize 11

title 予測月間コスト — 220M 入力 + 1,9M 出力
rectangle &amp;quot;Ollama Cloud Pro
約20ユーロ&amp;quot; as OC #4CAF50
rectangle &amp;quot;Gemini Flash
\$69&amp;quot; as GF #8BC34A
rectangle &amp;quot;DeepSeek promo
$98&amp;quot; as DSP #FFC107
rectangle &amp;quot;GPT Mini
$174&amp;quot; as GM #FF9800
rectangle &amp;quot;Claude Haiku
$230&amp;quot; as CH #FF5722
rectangle &amp;quot;HF/Novita
\$374&amp;quot; as HF #F44336
rectangle &amp;quot;DeepSeek 標準
$390&amp;quot; as DSN #F44336
rectangle &amp;quot;GPT 5.4
$579&amp;quot; as G4 #D32F2F
rectangle &amp;quot;Claude Sonnet
$689&amp;quot; as CS #D32F2F
rectangle &amp;quot;Claude Opus
$1,148&amp;quot; as CO #B71C1C
rectangle &amp;quot;GPT 5.5
$1 157&amp;quot; as G5 #880E4F

note bottom of OC
  DeepSeek V4 Pro 1.6T MoE
  + accès à tout le catalogue
  Ollama Cloud (Qwen, GLM, Kimi...)
  Inclus dans l&amp;#39;abonnement
end note
@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_隠れたコストプロンプトエンジニアリングとイテレーション&amp;quot;&amp;gt;�隠れたコスト：プロンプトエンジニアリングとイテレーション&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;トークンのコストは方程式の一部にすぎません。本当のコストは開発者の時間です。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;OpenCode + Ollama Cloud Pro + 私のエージェントガバナンス (EAGER/LAZY/Hot/Warm/Cold, &amp;lt;a href=&amp;quot;0108_gouvernance_agent_opencode_eager_lazy_post.html&amp;quot;&amp;gt;l&amp;amp;#8217;article sur la gouvernance&amp;lt;/a&amp;gt;) で説明 を使用すると、その結果、次のように得られます：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;0 反復的なプロンプトエンジニアリング&amp;lt;/strong&amp;gt;: コンテキストは自動的に注入されます&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;90%+ 初回正解&amp;lt;/strong&amp;gt;: コードは最初の試みでコンパイルされる&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;DeepSeek は 8 回連続のセッションで幻覚ゼロ&amp;lt;/strong&amp;gt;(以下に文書化されています &amp;lt;a href=&amp;quot;0112_comparaison_kimi_glm_deepseek_long_contexte_plugin_gradle_opencode_post.html&amp;quot;&amp;gt;Kimi/GLM/DeepSeekの比較&amp;lt;/a&amp;gt;)&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;ClaudeまたはGPT ファインチューンなし、ガバナンスなし：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;タスクごとに平均 2-3 回のイテレーション&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;体系的なプロンプトエンジニアリング&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;Kotlin/Gradle API の幻覚は、コンテキストが 30K トークンを超えるとすぐに現れる&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;月間の「効果的」コスト — tokens × itérations × temps de correction — は、私のソリューションの27倍から54倍であり、これは &amp;lt;a href=&amp;quot;0122_ratio_efficacite_27x_45x_flotte_experts_ia_vs_claude_gpt_post.html&amp;quot;&amp;gt;l&amp;amp;#8217;article sur le ratio d&amp;amp;#8217;efficacité&amp;lt;/a&amp;gt; で私が示したとおりです。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;em&amp;gt;&amp;lt;em&amp;gt;_ これはトークンあたりの価格の話だけではない。57倍の価格のClaude Opusは、3倍多くのイテレーションを必要とし、実質的なコストは約170倍高くなる。率直に言うと：McKinseyのパートナーの給料でインターンを雇うようなものだ。 &amp;lt;/em&amp;gt;_&amp;lt;/em&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_ollama_cloud_proのサブスクリプションを累積するdockerメソッド&amp;quot;&amp;gt;Ollama Cloud Proのサブスクリプションを累積する：Dockerメソッド&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;1つのサブスクリプションでは足りない場合は、それらを組み合わせます。原則として、各サブスクリプションをそれぞれのOllamaインストールに隔離し、それぞれのSSH認証キーを使います。Dockerならこれがとても簡単です。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;完全な方法は &amp;lt;a href=&amp;quot;0120_cumuler_deux_abonnements_ollama_pro_docker_post.html&amp;quot;&amp;gt;Dockerの累積に関する記事&amp;lt;/a&amp;gt; で詳しく説明されています。これが原則です：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
skinparam backgroundColor #FEFEFE
skinparam defaultFontSize 12

title アーキテクチャ — Ollama Cloud Proの2つのサブスクリプションを1台のマシンで
left to right direction

node &amp;quot;私の物理マシン&amp;quot; {
  frame &amp;quot;Ollama インスタンス A (ネイティブ)
ポート :11434&amp;quot; as Native {
    database &amp;quot;アイデンティティ A
/usr/share/ollama/.ollama/id_ed25519&amp;quot;
  }
  frame &amp;quot;オラマ インスタンス B (ドッカー)
ポート:11435&amp;quot; as Docker {
    database &amp;quot;アイデンティティ B
~/ollama-b-data/id_ed25519&amp;quot;
  }
}

cloud &amp;quot;Ollama Cloud&amp;quot; {
  actor &amp;quot;プロアカウント A
(メール 1)&amp;quot; as A
  actor &amp;quot;プロBアカウント\n(email 2)&amp;quot; as B
}

Native --&amp;amp;gt; A : &amp;quot;デバイスキーA&amp;quot;
Docker --&amp;amp;gt; B : &amp;quot;デバイスキー B&amp;quot;

note bottom of Docker
  Conteneur Docker isolé :
  - Clé SSH distincte
  - Port réseau distinct (11435)
  - Volume persistant (~/ollama-b-data)
  - restart: always
end note
@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;パターンは単純です :&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;olist arabic&amp;quot;&amp;gt;
&amp;lt;ol class=&amp;quot;arabic&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;ボリュームを作成`~/ollama-b-data`&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;ドッカーコンテナを実行する`ollama/ollama:0.20.2`にマッピングされた`11435:11434`&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;コンテナのSSHキーを取得 → ollama.comに保存する&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;する`ollama signin`二番目のメールとともに&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;OpenCodeを2つのプロバイダーで設定する (`ollama`で :11434,`ollama-b`について :11435)&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ol&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;アカウント2つ、青いカード1枚、競合ゼロ&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_監査が測らないもの&amp;quot;&amp;gt;監査が測らないもの&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;table class=&amp;quot;tableblock frame-all grid-all stretch&amp;quot;&amp;gt;
&amp;lt;colgroup&amp;gt;
&amp;lt;col style=&amp;quot;width: 40%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 60%;&amp;quot;&amp;gt;
&amp;lt;/colgroup&amp;gt;
&amp;lt;thead&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;th class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;�盲点&amp;lt;/th&amp;gt;
&amp;lt;th class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;インパクト&amp;lt;/th&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/thead&amp;gt;
&amp;lt;tbody&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;生成コードの品質&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;26億トークンはコードがコンパイルするかどうかを言わない。私のDeepSeek V4 Proの8つのセッションは、ファーストショット成功率が90%以上である。&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;エコシステム OpenCode&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;CLIは無料ですが、その価値（エージェント、サンドボックス、履歴、プロンプトキャッシング）は非常に大きいです。サブスクリプションの価格に含まれていません — 別のツールです。&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;機会コスト&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;1日2時間、性能の劣るモデルの幻覚をデバッグするのに費やす時間は、月20ユーロ以上かかる。&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;心の平安&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;固定プランはサプライズなし。従量課金では、利用の急増が大きな打撃になることがあります。&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/tbody&amp;gt;
&amp;lt;/table&amp;gt;
&amp;lt;div class=&amp;quot;admonitionblock warning&amp;quot;&amp;gt;
&amp;lt;table&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;icon&amp;quot;&amp;gt;
&amp;lt;i class=&amp;quot;fa icon-warning&amp;quot; title=&amp;quot;⚠️&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;
&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;引用された価格は2026年5月のものです。6か月後にはすべてが下がっているでしょう。しかし、構造的な力関係 — 定額制対従量制 — は、大量消費者にとって定額制に有利なまま残るでしょう。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/table&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_結論数字の裁定&amp;quot;&amp;gt;結論：数字の裁定&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;73日後、1 022セッション OpenCode、および2.6億トークン：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;table class=&amp;quot;tableblock frame-all grid-all stretch&amp;quot;&amp;gt;
&amp;lt;colgroup&amp;gt;
&amp;lt;col style=&amp;quot;width: 60%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 40%;&amp;quot;&amp;gt;
&amp;lt;/colgroup&amp;gt;
&amp;lt;thead&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;th class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;メトリック&amp;lt;/th&amp;gt;
&amp;lt;th class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;判決&amp;lt;/th&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/thead&amp;gt;
&amp;lt;tbody&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;累積外部 API コスト&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;$0.22&amp;lt;/strong&amp;gt;(ほぼゼロ)&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;Ollama Cloud Proの料金&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;約20ユーロ/月&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;「Claude Opus」相当&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;\$1,148/月&amp;lt;/strong&amp;gt;— 57倍高価&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;GPT 5.5相当&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;\$1 157/月&amp;lt;/strong&amp;gt;— 58倍高い&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;HuggingFace/Novitaの同等物&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;\$374/mois&amp;lt;/strong&amp;gt;— 19× もっと高い&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;DeepSeek API の直接の同等物&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;\$390/月&amp;lt;/strong&amp;gt;— 20倍高い&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;最も安い同等物 (Gemini Flash)&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;$69/月&amp;lt;/strong&amp;gt;— 3,5×高価な, 下位モデル&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;市場で最高のオファー&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;Ollama Cloud Pro 月額20ユーロ&amp;lt;/strong&amp;gt;— 無敵&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/tbody&amp;gt;
&amp;lt;/table&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;em&amp;gt;__&amp;lt;/em&amp;gt; Ollama Cloud を通じて DeepSeek V4 Pro (1.6T パラメータ, MoE, CSA+HCA, 1M コンテキスト) に月額 20 ユーロでアクセスできることから、私は世界市場で最高のコストパフォーマンスを得ています。中国の直接のプロバイダーでも 5 倍から 20 倍高いです。低コスト プロバイダーの集約を行う HuggingFace でも 19 倍高いです。西洋市場 (Claude, GPT) は 50-60 倍 — まるで別の惑星です。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;この比率は極端に不均衡すぎて、永遠に続くことはできません。それが存在している間に利用せよ。 &amp;amp;lt;/think&amp;amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;そう、毎月の20ユーロが私の開発者人生で最高の技術的投資だ。それによって今、それを証明する数字があなたにはある。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;hr&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_参考文献&amp;quot;&amp;gt;参考文献&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;0108_gouvernance_agent_opencode_eager_lazy_post.html&amp;quot;&amp;gt;Article 0108 — ガバナンス エージェント EAGER/LAZY/Hot/Warm/Cold&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;記事 0112 — DeepSeek V4 Pro vs Kimi K2.6 vs GLM 5.1&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;0119_benchmark_dgx_spark_vs_cloud_abonnement_llm_post.html&amp;quot;&amp;gt;Article 0119 — Benchmark DGX Spark vs Cloud vs Abonnements LLM&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;0120_cumuler_deux_abonnements_ollama_pro_docker_post.html&amp;quot;&amp;gt;記事 0120 — Ollama Cloud Pro と Docker を組み合わせた 2 つのサブスクリプション&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;0121_plugin_gradle_piloter_deux_instances_ollama_pro_post.html&amp;quot;&amp;gt;記事0121 — Gradleプラグインで2つのOllamaインスタンスを操作&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;0122_ratio_efficacite_27x_45x_flotte_experts_ia_vs_claude_gpt_post.html&amp;quot;&amp;gt;記事0122 — 効率比率 27倍 から 54倍&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_料金の出所&amp;quot;&amp;gt;料金の出所&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;https://ollama.com/pricing&amp;quot;&amp;gt;Ollama Cloud — Proプラン $20/月&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;https://api-docs.deepseek.com/quick_start/pricing&amp;quot;&amp;gt;DeepSeek API — 公式料金 V4 Pro&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;https://platform.kimi.com/docs/pricing/chat-k26&amp;quot;&amp;gt;Kimi Moonshot — 料金 K2.6&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;https://huggingface.co/inference/models&amp;quot;&amp;gt;HuggingFace Inference Providers — プロバイダーごとの料金&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;https://www.anthropic.com/pricing&amp;quot;&amp;gt;Anthropic — Claude API 料金&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;https://openai.com/api/pricing/&amp;quot;&amp;gt;OpenAI — GPT APIの料金&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;https://together.ai/pricing&amp;quot;&amp;gt;Together AI — 推論料金&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;https://groq.com/pricing&amp;quot;&amp;gt;Groq — API料金&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;https://deepinfra.com/pricing&amp;quot;&amp;gt;DeepInfra — GPUの価格とモデル&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;https://help.aliyun.com/zh/model-studio/text-generation-model/&amp;quot;&amp;gt;Alibaba Bailian — 利用可能なモデル&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;https://github.com/anomalyco/opencode&amp;quot;&amp;gt;OpenCode — GitHubのオープンソースCLI&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;</description>
        </item><item>
            <title>プラグイン独立＋コンシューマー ルート アーキテクチャ：なぜ私のGradleビルドが重複するのか</title>
            <link >https://cheroliv.com/blog/2026/0124_architecture_plugin_gradle_racine_consommateur_independant_post.html</link>
            <pubDate>Thu, 14 May 2026 00:00:00 +0000</pubDate>
            <guid isPermaLink="false">blog/2026/0124_architecture_plugin_gradle_racine_consommateur_independant_post.html</guid>
            <description>&amp;lt;div id=&amp;quot;toc&amp;quot; class=&amp;quot;toc&amp;quot;&amp;gt;
&amp;lt;div id=&amp;quot;toctitle&amp;quot;&amp;gt;Table des matières&amp;lt;/div&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel1&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_問題私の時間を奪った3つのアーキテクチャ&amp;quot;&amp;gt;問題：私の時間を奪った3つのアーキテクチャ&amp;lt;/a&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel2&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_オプション_1_分離されたプラグイン_ドッグフーディングなし&amp;quot;&amp;gt;オプション 1 : 分離されたプラグイン (ドッグフーディングなし)&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_option_2_クラシックなモノリポ_includeplugin&amp;quot;&amp;gt;Option 2 : クラシックなモノリポ (&amp;lt;code&amp;gt;include(&amp;quot;:plugin&amp;quot;)&amp;lt;/code&amp;gt;)&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_オプション_3_コンポジット_ビルド_includebuild&amp;quot;&amp;gt;オプション 3 : コンポジット ビルド (&amp;lt;code&amp;gt;includeBuild()&amp;lt;/code&amp;gt;)&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_ソリューション独立した2つのビルド1つの消費者ルート&amp;quot;&amp;gt;ソリューション：独立した2つのビルド、1つの消費者ルート&amp;lt;/a&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel2&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_ワークフロー&amp;quot;&amp;gt;ワークフロー&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_具体的なワークフロー&amp;quot;&amp;gt;具体的なワークフロー&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_なぜこのアーキテクチャが私を魅了した&amp;quot;&amp;gt;なぜこのアーキテクチャが私を魅了した&amp;lt;/a&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel2&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_1_ネイティブドッグフーディング即時フィードバック&amp;quot;&amp;gt;1. ネイティブドッグフーディング、即時フィードバック&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_2_ゼロコンフィグ_クローニング&amp;quot;&amp;gt;2. ゼロコンフィグ クローニング&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_3_ビルドの分離_ci_の独立&amp;quot;&amp;gt;3. ビルドの分離, CI の独立&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_サブフォルダー_name_plugin_の構造&amp;quot;&amp;gt;サブフォルダー &amp;lt;code&amp;gt;{name}-plugin/&amp;lt;/code&amp;gt; の構造&amp;lt;/a&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel2&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_バージョンカタログ_2つの異なるファイル&amp;quot;&amp;gt;バージョンカタログ : 2つの異なるファイル&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_私たちがやらないこと&amp;quot;&amp;gt;私たちがやらないこと&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_比較ドッグフーディングに直面する3つのアーキテクチャ&amp;quot;&amp;gt;比較：ドッグフーディングに直面する3つのアーキテクチャ&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_dag契約_サブディレクトリからはルートビルドが決して行われない&amp;quot;&amp;gt;DAG契約 : サブディレクトリからはルートビルドが決して行われない&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_結論時間を節約する見かけの重複&amp;quot;&amp;gt;結論：時間を節約する見かけの重複&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_参照&amp;quot;&amp;gt;参照&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div id=&amp;quot;preamble&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;読了時間 : 11 minutes&amp;lt;/div&amp;gt;
&amp;lt;p&amp;gt;Gradleプラグインのリポジトリをクローンしています。ターミナルを開いています。何を入力していますか？ その後？&amp;lt;code&amp;gt;./gradlew tasks&amp;lt;/code&amp;gt;, 当然です。 しかし、どのフォルダーですか？ ルートですか？ サブモジュールですか？ まずREADMEを読んでビルド方法を確認すべきでしょうか？もし躊躇しているなら 一瞬で、プロジェクトのアーキテクチャーが壊れています。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;これが私がこの問題を一度限りで解決した方法 — そしてなぜこれが パターンは今日、私のすべてのGradleプラグインの署名の中`foundry/public/`.&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_問題私の時間を奪った3つのアーキテクチャ&amp;quot;&amp;gt;問題：私の時間を奪った3つのアーキテクチャ&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;現在のパターンに収束する前に、私は3つのアプローチの間で試行錯誤した Gradle プラグインを構成するための伝統的な方法。それぞれに致命的な欠陥があった。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_オプション_1_分離されたプラグイン_ドッグフーディングなし&amp;quot;&amp;gt;オプション 1 : 分離されたプラグイン (ドッグフーディングなし)&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;プロジェクトにはプラグインのみが含まれます。 消費の例はありません。 なし プロジェクトがそれを行う。それをテストするには、外部のプロジェクトを作成する必要があります、y プラグインを介して参照する`mavenLocal`または複合ビルド、そしてのみ そこでそれが動くことを確認する。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-shell hljs&amp;quot; data-lang=&amp;quot;shell&amp;quot;&amp;gt;$ git clone mon-plugin
$ cd mon-plugin
$ ./gradlew build          # le plugin compile
$ # ... et maintenant ? comment je l&amp;#39;essaie ?&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;admonitionblock warning&amp;quot;&amp;gt;
&amp;lt;table&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;icon&amp;quot;&amp;gt;
&amp;lt;i class=&amp;quot;fa icon-warning&amp;quot; title=&amp;quot;⚠️&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;
&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;消費例のない Gradle プラグインは、ライブラリではない 統合テスト。 あなたは最後の変更が ユーザー体験を壊した&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/table&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_option_2_クラシックなモノリポ_includeplugin&amp;quot;&amp;gt;Option 2 : クラシックなモノリポ (&amp;lt;code&amp;gt;include(&amp;quot;:plugin&amp;quot;)&amp;lt;/code&amp;gt;)&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;グレードル`init`生成する`settings.gradle.kts`と`include(&amp;quot;plugin&amp;quot;)`. ルートとサブモジュールは同じデーモンと同じ設定を共有します、 同じカタログです。便利ですが、結合されています。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-text hljs&amp;quot; data-lang=&amp;quot;text&amp;quot;&amp;gt;.
├── settings.gradle.kts   → include(&amp;quot;plugin&amp;quot;)
├── build.gradle.kts      → plugins { id(&amp;quot;mon-plugin&amp;quot;) }
├── plugin/
│   └── build.gradle.kts  → java-gradle-plugin
└── gradle/
    └── libs.versions.toml&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;ネックは：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;ルート&amp;lt;strong&amp;gt;しなければならない&amp;lt;/strong&amp;gt;サブモジュールと同じGradleのバージョンを持つ。&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;`libs.versions.toml`共有されている — 共通のバージョンカタログ、依存関係&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;モジュールから別のモジュールへ逃げている&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;ルートなしではプラグインをビルドすることはできません。&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;CIはプラグインのみが変更された場合でも、2つのモジュールをビルドしなければならない。&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_オプション_3_コンポジット_ビルド_includebuild&amp;quot;&amp;gt;オプション 3 : コンポジット ビルド (&amp;lt;code&amp;gt;includeBuild()&amp;lt;/code&amp;gt;)&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;2つをそれぞれ異なるGradleビルドに分け、それらを経由でつなげる &amp;lt;code&amp;gt;includeBuild(&amp;quot;mon-plugin&amp;quot;)`中に`settings.gradle.kts&amp;lt;/code&amp;gt;。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;既に改善されました。プラグインのビルドは分離されています。しかし、消費者 明示的に外部ビルドを参照しなければならない — 出力は `./gradlew tasks`根本では、正しい設定に依存する 複合体。クローン作成はzero-configではありません：それが…であることを知っておく必要があります プラグインは別のフォルダーにあり、ルートがそれを参照しているなど。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-shell hljs&amp;quot; data-lang=&amp;quot;shell&amp;quot;&amp;gt;.
├── settings.gradle.kts   → includeBuild(&amp;quot;plugin-build/&amp;quot;)
├── build.gradle.kts      → plugins { id(&amp;quot;mon-plugin&amp;quot;) }
└── plugin-build/
    ├── settings.gradle.kts
    └── build.gradle.kts&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;もっと良いものを探していた。ずっと良いもの。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_ソリューション独立した2つのビルド1つの消費者ルート&amp;quot;&amp;gt;ソリューション：独立した2つのビルド、1つの消費者ルート&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;こちらが最終的に採用したパターンです：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-text hljs&amp;quot; data-lang=&amp;quot;text&amp;quot;&amp;gt;.
├── settings.gradle.kts          ← racine consommateur
├── build.gradle.kts              ← 3 lignes : apply plugin + dogfood
├── gradle/
│   └── libs.versions.toml        ← catalogue du consommateur
├── {name}-plugin/                ← BUILD INDÉPENDANT
│   ├── gradlew                    ← son propre wrapper
│   ├── settings.gradle.kts        ← rootProject.name = &amp;quot;{name}-plugin&amp;quot;
│   ├── build.gradle.kts           ← java-gradle-plugin, signing, publish
│   ├── gradle/
│   │   ├── libs.versions.toml     ← catalogue du plugin
│   │   └── wrapper/
│   ├── src/                       ← sources du plugin
│   ├── .agents/                   ← gouvernance agent
│   └── *.adoc                     ← AGENT, PROMPT_REPRISE, snapshot, etc.
└── site.yml / slides-context.yml / ...   ← configs dogfood&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;admonitionblock important&amp;quot;&amp;gt;
&amp;lt;table&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;icon&amp;quot;&amp;gt;
&amp;lt;i class=&amp;quot;fa icon-important&amp;quot; title=&amp;quot;❗&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;
&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;�鍵:`{name}-plugin/`完全かつ独立したGradleプロジェクト。 彼には独自の wrapper、独自の settings、独自の catalogue の バージョン。自身をクローンし、ビルドし、テストし、そして root なしで公開します。 その存在を知っているかどうか&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/table&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;ルートは、*一つ*のことだけを行う：プラグインを適用する。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-kotlin hljs&amp;quot; data-lang=&amp;quot;kotlin&amp;quot;&amp;gt;plugins {
    alias(libs.plugins.bakery)
}

repositories {
    mavenLocal()
    mavenCentral()
}

bakery { configPath = file(&amp;quot;site.yml&amp;quot;).absolutePath }&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;ケースでは3行`bakery-gradle`. それ以上はありません。 ゼロ`include()&amp;lt;code&amp;gt;, ゼロ`includeBuild()&amp;lt;/code&amp;gt;, ゼロのサブプロジェクト。 通常のGradleビルドは、任意のプラグインを適用します どの消費者がそれをするでしょうか。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_ワークフロー&amp;quot;&amp;gt;ワークフロー&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
skinparam backgroundColor #FEFEFE
skinparam defaultFontSize 12

left to right direction

package &amp;quot;根 (消費者)&amp;quot; #CCFFCC {
    usecase &amp;quot;リポジトリをクローン&amp;quot; as Clone
    usecase &amp;quot;./gradlew tasks&amp;quot; as Tasks
    usecase &amp;quot;./gradlew bake&amp;quot; as Dogfood
    note bottom of Dogfood
        Exerce le plugin
        Feedback immédiat
        Zéro config
    end note
}

package &amp;quot;{name}-plugin/ (独立したビルド)&amp;quot; #CCE5FF {
    usecase &amp;quot;./gradlew build&amp;quot; as BuildPlugin
    usecase &amp;quot;./gradlew publishToMavenLocal&amp;quot; as MavenLocal
    usecase &amp;quot;./gradlew test&amp;quot; as TestPlugin
    note bottom of BuildPlugin
        Cycle de vie isolé
        Tests unitaires + Cucumber
        CI dédiée possible
    end note
}

Clone -down-&amp;amp;gt; Tasks
Tasks -down-&amp;amp;gt; Dogfood
Dogfood ..&amp;amp;gt; MavenLocal : &amp;quot;プラグインに依存します
ローカルで公開&amp;quot;
BuildPlugin -up-&amp;amp;gt; MavenLocal
TestPlugin -up-&amp;amp;gt; BuildPlugin

@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_具体的なワークフロー&amp;quot;&amp;gt;具体的なワークフロー&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-shell hljs&amp;quot; data-lang=&amp;quot;shell&amp;quot;&amp;gt;# 1. Builder le plugin
$ cd codebase-plugin
$ ./gradlew publishToMavenLocal

# 2. L&amp;#39;exercer depuis la racine
$ cd ..
$ ./gradlew indexCodebase queryCodebase snapshot

# La boucle est fermée. Le plugin est testé dans des conditions
# réelles de consommation, par le projet même qui l&amp;#39;héberge.&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_なぜこのアーキテクチャが私を魅了した&amp;quot;&amp;gt;なぜこのアーキテクチャが私を魅了した&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;組み合わせるとコストに見合う３つの利点：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_1_ネイティブドッグフーディング即時フィードバック&amp;quot;&amp;gt;1. ネイティブドッグフーディング、即時フィードバック&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;Gradleプラグインの最良のテストは、それを使うことです。 モックされたユニットテストではない。でもない`GradleRunner`プロジェクトと共に テストの。プラグインを本当のファイルに適用する*本当の*ビルド&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-shell hljs&amp;quot; data-lang=&amp;quot;shell&amp;quot;&amp;gt;$ git clone bakery-gradle
$ cd bakery-gradle
$ ./gradlew bake    # ← le plugin est exercé immédiatement&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;プラグインが壊れているとき、ルートビルドはそれを教えてくれます。わざわざ確認しに行く必要はありません。 外部のテストプロジェクトを探す。ドッグフーディングは*最初的*だ 新しい貢献者が開始するタスク。それが最終的なスモークテストです。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;admonitionblock tip&amp;quot;&amp;gt;
&amp;lt;table&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;icon&amp;quot;&amp;gt;
&amp;lt;i class=&amp;quot;fa icon-tip&amp;quot; title=&amp;quot;💡&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;
&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;ルールはシンプルです : もしルートがコンパイルされ、そして`./gradlew tasks` あなたのプラグインのタスクを表示し、プラグインは機能しています。驚きはありません 本番で。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/table&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_2_ゼロコンフィグ_クローニング&amp;quot;&amp;gt;2. ゼロコンフィグ クローニング&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;Un `git clone &amp;amp;amp;&amp;amp;amp; ./gradlew tasks`そして新参者はすべてを見る 設定せずに歩く。 その`build.gradle.kts`根は プラグインの使用に関する生きているドキュメント。 Le`site.yml`横に 期待される構成を示します。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;代替案と比較して：3段落のREADMEが プラグインをビルドする方法とプロジェクトをビルドする方法を説明します のテスト。 新しい貢献者はREADMEを斜めに読む, 間違って、issue を開ける — しかし情報は である &amp;lt;strong&amp;gt;実行可能&amp;lt;/strong&amp;gt;。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;admonitionblock important&amp;quot;&amp;gt;
&amp;lt;table&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;icon&amp;quot;&amp;gt;
&amp;lt;i class=&amp;quot;fa icon-important&amp;quot; title=&amp;quot;❗&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;
&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;最も堅牢なドキュメントは読むものではない。 それは&amp;lt;strong&amp;gt;実行&amp;lt;/strong&amp;gt;. ルートビルドはドキュメントです プラグインの実行可能ファイル&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/table&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_3_ビルドの分離_ci_の独立&amp;quot;&amp;gt;3. ビルドの分離, CI の独立&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;プラグインは独自のGradleラッパーと、独自のライフサイクルを持ち、 独自のテスト。できること:&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;プラグインでGradleをアップグレードし、rootを触らない&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;ルートに漏れないようにプラグインに依存関係を追加する&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;プラグインを壊して、ルート ビルドに影響を与えずに (ただし、あなたが&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;壊れたバージョンを公開するな)&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;プラグインをビルド/テストするCIと、それを行使するもう一方のCI&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;root — 独立して&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-text hljs&amp;quot; data-lang=&amp;quot;text&amp;quot;&amp;gt;.github/workflows/
├── test-plugin.yml      → codebase-plugin/.gradlew build
├── test-root.yml        → .gradlew tasks (vérifie que le plugin est consommable)
└── publish.yml          → codebase-plugin/.gradlew publish&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_サブフォルダー_name_plugin_の構造&amp;quot;&amp;gt;サブフォルダー &amp;lt;code&amp;gt;{name}-plugin/&amp;lt;/code&amp;gt; の構造&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;プラグインのフォルダに存在するものを詳しく見てみましょう：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-text hljs&amp;quot; data-lang=&amp;quot;text&amp;quot;&amp;gt;codebase-plugin/
├── gradlew                           ← wrapper indépendant
├── settings.gradle.kts               ← @Suppress(&amp;quot;UnstableApiUsage&amp;quot;)
│                                       + foobar-resolver-convention
├── build.gradle.kts                  ← java-gradle-plugin + signing + publish
├── gradle/
│   ├── libs.versions.toml            ← catalogue complet (langchain4j, pgvector...)
│   └── wrapper/
├── buildSrc/                         ← classes utilitaires buildSrc
│   ├── build.gradle.kts
│   └── src/main/kotlin/
│       ├── codebase/                 ← CodebaseYmlAnonymizer, CodebaseConfiguration
│       ├── benchmark/                ← BenchmarkConfig, BenchmarkProtocol
│       ├── readme/                   ← ReadmeYmlAnonymizer
│       ├── site/                     ← SiteYmlAnonymizer
│       ├── slider/                   ← SliderYmlAnonymizer
│       └── snapshot/                 ← SnapshotManager
├── src/
│   ├── main/kotlin/codebase/
│   │   ├── CodebasePlugin.kt         ← class Plugin&amp;amp;lt;Project&amp;amp;gt;
│   │   ├── rag/                      ← pgvector, embedding, anonymization...
│   │   ├── benchmark/                ← BenchmarkRunner, export, comparison...
│   │   └── walker/                   ← WorkspaceWalker
│   └── test/
│       ├── kotlin/codebase/scenarios/ ← steps Cucumber
│       ├── features/                  ← .feature files
│       └── resources/datasets/        ← fixtures .adoc, .yml, .json
├── .agents/                          ← gouvernance agent (INDEX, SESSIONS, etc.)
├── AGENT.adoc                        ← règles agent
├── PROMPT_REPRISE.adoc              ← mission session
├── BACKLOG.adoc                      ← backlog produit
├── snapshot.adoc                     ← snapshot auto-généré du projet
└── embeds.yml                        ← config RAG embeds&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;すべてそこにある。ルートとサブフォルダーの間に散らばりはない。 プラグインで作業する開発者は決して…する必要がない 去る`codebase-plugin/`. プラグインを使用する開発者 根だけを見 — そして`build.gradle.kts`3行の 彼は彼に必要なことをすべて伝える。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_バージョンカタログ_2つの異なるファイル&amp;quot;&amp;gt;バージョンカタログ : 2つの異なるファイル&amp;lt;/h3&amp;gt;
&amp;lt;table class=&amp;quot;tableblock frame-all grid-all stretch&amp;quot;&amp;gt;
&amp;lt;colgroup&amp;gt;
&amp;lt;col style=&amp;quot;width: 25%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 37.5%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 37.5%;&amp;quot;&amp;gt;
&amp;lt;/colgroup&amp;gt;
&amp;lt;tbody&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;code&amp;gt;gradle/libs.versions.toml&amp;lt;/code&amp;gt;(根)&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;code&amp;gt;{name}-plugin/gradle/libs.versions.toml&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;依存関係の数&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;2-3 (プラグイン + README オプション)&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;30+ (langchain4j, pgvector, cucumber&amp;amp;#8230;&amp;amp;#8203;)&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;役割&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;プラグインを消費する&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;プラグインをビルド&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;それを読む人&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;プラグインの利用者&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;プラグインの開発者&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/tbody&amp;gt;
&amp;lt;/table&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;ルートは意図的に最小限のカタログを持っています。プラグインはカタログを持っています。 完了。 混同は不可能です：各ビルドはそれぞれ固有のスコープを持ちます。 依存関係の。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;admonitionblock note&amp;quot;&amp;gt;
&amp;lt;table&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;icon&amp;quot;&amp;gt;
&amp;lt;i class=&amp;quot;fa icon-note&amp;quot; title=&amp;quot;ℹ️&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;
&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;依存関係の衝突をデバッグするのに既に1時間以上費やしたことがある場合 あなたのプラグインとテストプロジェクトの間で、その価値がわかる この分離。独立したカタログはこの問題を解消します 構成により。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/table&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_私たちがやらないこと&amp;quot;&amp;gt;私たちがやらないこと&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;このパターンは魔法的ではない。私が課す制約がある 喜んで私に課す：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;ルートはプラグインをビルドしません。&amp;lt;/strong&amp;gt; あなたは`publishToMavenLocal` ou root がそれを消費する前に、リポジトリにデプロイする。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;これは最小限のコストです。そしてそれが*適切な*制約です。ルート プラグインを外部クライアントのように消費する — Mavenを通じて。確かに サードパーティプロジェクトが行うように。プラグインが公開できない場合、 root がすぐに教えてくれます。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-shell hljs&amp;quot; data-lang=&amp;quot;shell&amp;quot;&amp;gt;# La seule &amp;quot;friction&amp;quot; du pattern
$ cd codebase-plugin &amp;amp;amp;&amp;amp;amp; ./gradlew publishToMavenLocal &amp;amp;amp;&amp;amp;amp; cd ..
$ ./gradlew tasks --group=codebase&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_比較ドッグフーディングに直面する3つのアーキテクチャ&amp;quot;&amp;gt;比較：ドッグフーディングに直面する3つのアーキテクチャ&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;table class=&amp;quot;tableblock frame-all grid-all stretch&amp;quot;&amp;gt;
&amp;lt;colgroup&amp;gt;
&amp;lt;col style=&amp;quot;width: 20%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 20%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 20%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 20%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 20%;&amp;quot;&amp;gt;
&amp;lt;/colgroup&amp;gt;
&amp;lt;tbody&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;隔離されたプラグイン&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;モノレポ`include()`&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;複合`includeBuild()`&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;ルート + 独立プラグイン&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;`git clone &amp;amp;amp;&amp;amp;amp; gradlew tasks`プラグインのタスクを与える&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;❌&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;�✅&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;✅&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;(No output, as there is no French text provided to translate)&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;ルートに依存しないビルドプラグイン&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;�✅&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;�❌&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;�✅&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;�✅&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;バージョン別カタログ&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;�✅&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;�❌&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;�✅&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;✅&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;ない`include()` ni &amp;lt;code&amp;gt;includeBuild()&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;�✅&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;�❌&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;❌&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;�✅&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;設定なしのネイティブドッグフード&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;❌&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;✅&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;⚠️&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;amp;lt;/think&amp;amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;独立したCIプラグイン&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;�✅&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;❌&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;(empty string)&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;✅&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;ルートは実際の消費の例&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;(Empty)&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;⚠️&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;�✅&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;amp;lt;/think&amp;amp;gt; (No output as there is no French text provided to translate)&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/tbody&amp;gt;
&amp;lt;/table&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;右�側の列はすべてのチェックボックスにチェックを入れます。それが理由で私は さらに後ろに戻ります。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_dag契約_サブディレクトリからはルートビルドが決して行われない&amp;quot;&amp;gt;DAG契約 : サブディレクトリからはルートビルドが決して行われない&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;このアーキテクチャは自然にDAG N0→N3に組み込まれます。 私のワークスペースから。パターンは：*プラグインN2はハブ 自身の依存関係において、N3のルートは終端です。 ハブ*を適用する&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
skinparam backgroundColor #FEFEFE
skinparam defaultFontSize 11

title DAG契約 — コンシューマールート vs 独立プラグイン
package &amp;quot;N3 — 根 (預金)&amp;quot; #FFCCCC {
    [build.gradle.kts (3 lignes)] as ROOT
    [libs.versions.toml (minimal)] as ROOT_TOML
    note right of ROOT
        plugins { bakery }
        bakery { configPath = ... }
        Aucune logique métier
    end note
}

package &amp;quot;N2 — {name}-プラグイン/&amp;quot; #CCFFCC {
    [build.gradle.kts (complet)] as PLUGIN
    [src/main/kotlin/] as SRC
    [gradle/libs.versions.toml] as PLUGIN_TOML
    [buildSrc/] as BUILDSRC
    note bottom of PLUGIN
        java-gradle-plugin
        signing + publish
        Tests unitaires + Cucumber
        CI dédiée
    end note
}

ROOT_TOML --&amp;amp;gt; ROOT : &amp;quot;バージョン プラグイン&amp;quot;
ROOT -down-&amp;amp;gt; PLUGIN : &amp;quot;publishToMavenLocal&amp;quot;
@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;Le &amp;lt;code&amp;gt;codebase-gradle/build.gradle.kts`6行です。 なし`src/&amp;lt;/code&amp;gt;, ない`buildSrc/&amp;lt;code&amp;gt;, なし`gradle/rag-bench.gradle.kts&amp;lt;/code&amp;gt;. 正しい &amp;lt;code&amp;gt;plugins { alias(libs.plugins.codebase) }`そしてリポジトリ。 すべての複雑さはそこにある`codebase-plugin/&amp;lt;/code&amp;gt;。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_結論時間を節約する見かけの重複&amp;quot;&amp;gt;結論：時間を節約する見かけの重複&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;誰かにこの構造を示すとき、最初の反応 よくある：「でも、あなたは二つ`gradlew`, 二`settings.gradle.kts`, 二`libs.versions.toml`— それはただの複製です！&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;はい。そしていいえ。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;「複製」は、同じ情報を2か所に再現すること。 ここで、これらは2つの*別々の*用途に使われる2つの*別々の*ファイルです： プラグインカタログ（30+ ビルダー用依存関係）およびカタログ ルートから(2-3の依存関係を消費する)。 プラグインのラッパー (開発用ロックされたバージョン) と ルートのラッパー (プラグインの演習用として、異なるバージョンである可能性があります).&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;これは複製ではありません。これは&amp;lt;strong&amp;gt;分離の �責任&amp;lt;/strong&amp;gt; ビルドシステムに適用された。 各ビルド 一つのことだけを行う。 ルートが消費する。 プラグインがビルドされる。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;コスト？ 一つの注文`publishToMavenLocal`プラグインのビルドの間 そしてルートのビルド。利点とは？建築的な明確さをもたらす 下流のデバッグに費やす時間を削減します。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;このパターンをデプロイして以来`bakery-gradle`, &amp;lt;code&amp;gt;plantuml-gradle&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;codebase-gradle&amp;lt;/code&amp;gt;, 他のプラグインの`foundry/public/&amp;lt;code&amp;gt;, 持っていません ターミナルを私のリポジトリの一つで開けたとき、二度とためらった。 最初の反射 —&amp;lt;/code&amp;gt;./gradlew tasks`— 歩み続け、常に与える 良いタスクを教えてくれ、すぐにすべてが健全かどうかを教えてくれる。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;それが良いアーキテクチャだ。それはREADMEには書かれていない。 端末でテストされ、10秒以内に完了します。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_参照&amp;quot;&amp;gt;参照&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;0105_integrer_graphify_workflow_gradle_post.html&amp;quot;&amp;gt;Article 0105 — Intégrer Graphify dans un workflow Gradle&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;0117_granularisation_oss_css_repositorie_workspace_post.html&amp;quot;&amp;gt;Article 0117 — La Granularisation OSS/CSS&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;記事 0123 — Knowledge Graph をレコメンデーション エンジンとして&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;</description>
        </item><item>
            <title>レコメンデーション エンジンとしての Knowledge Graph：私が時系列の「関連記事」をどう廃止したか</title>
            <link >https://cheroliv.com/blog/2026/0123_knowledge_graph_moteur_recommandation_articles_connexes_post.html</link>
            <pubDate>Tue, 12 May 2026 00:00:00 +0000</pubDate>
            <guid isPermaLink="false">blog/2026/0123_knowledge_graph_moteur_recommandation_articles_connexes_post.html</guid>
            <description>&amp;lt;div id=&amp;quot;toc&amp;quot; class=&amp;quot;toc&amp;quot;&amp;gt;
&amp;lt;div id=&amp;quot;toctitle&amp;quot;&amp;gt;Table des matières&amp;lt;/div&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel1&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_シーン_火曜日_5月12日_17時30&amp;quot;&amp;gt;シーン : 火曜日 5月12日 17時30&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_診断テンプレートが見逃す３つの関係のタイプ&amp;quot;&amp;gt;診断：テンプレートが見逃す３つの関係のタイプ&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_解決策gradle_パイプラインホットな_llm_呼び出しではない&amp;quot;&amp;gt;解決策：Gradle パイプライン、ホットな LLM 呼び出しではない&amp;lt;/a&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel2&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_アーキテクチャ_bakeryはgraphifyをインポートしエンジンはインポートしない&amp;quot;&amp;gt;アーキテクチャ : BakeryはGraphifyをインポートし、エンジンはインポートしない&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_パイプライン_スキャン_グラフ_テンプレート&amp;quot;&amp;gt;パイプライン: スキャン → グラフ → テンプレート&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_クロノロジカルフォールバック&amp;quot;&amp;gt;クロノロジカルフォールバック&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_エマージェントオントロジー_記事が互いを知らずに集まるとき&amp;quot;&amp;gt;エマージェントオントロジー : 記事が互いを知らずに集まるとき&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_dag契約誰が誰に重要か&amp;quot;&amp;gt;DAG契約：誰が誰に重要か&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_得られることと得られないこと&amp;quot;&amp;gt;得られることと得られないこと&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_視点パブリックナレッジグラフとしてのブログ&amp;quot;&amp;gt;視点：パブリックナレッジグラフとしてのブログ&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_結論ファイルシステムはテンプレートが無視するものを知っている&amp;quot;&amp;gt;結論：ファイルシステムはテンプレートが無視するものを知っている&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_参照&amp;quot;&amp;gt;参照&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div id=&amp;quot;preamble&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;読了時間 : 14 minutes&amp;lt;/div&amp;gt;
&amp;lt;p&amp;gt;あなたは pgvector と LangChain4j の統合に関する記事を読んでいます。ページの下部に、JBake 「関連記事」を提案されます。それをクリックします。それは…設定に関する記事です。 キティターミナルの。二つの間の唯一の共通点は？彼らは未満で公開されました 15日間隔。これは推奨ではありません。これは偽装されたカレンダーである 編集.&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_シーン_火曜日_5月12日_17時30&amp;quot;&amp;gt;シーン : 火曜日 5月12日 17時30&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;私は自分の記事の一つを読み返しています — &amp;lt;a href=&amp;quot;0106_knowledge_graph_outil_comprehension_codebase_post.html&amp;quot;&amp;gt;celui sur le Knowledge Graph comme outil de compréhension de codebase&amp;lt;/a&amp;gt; 内容は濃い：ノード、エッジ、コミュニティ、PlantUML、オンボーディング。記事 動員する15分間の読書テクニック`graphify-gradle`, &amp;lt;code&amp;gt;plantuml-gradle&amp;lt;/code&amp;gt;, およびグラフトポロジーの概念。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;ページ下部で、 「関連記事」 が提案しています：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;olist arabic&amp;quot;&amp;gt;
&amp;lt;ol class=&amp;quot;arabic&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;Firebase Contact Form (0113)の記事&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;Eager/Lazy メカニズムに関する記事(0108)&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;グラドルスクリプト→プラグインへの移行(0102)についての記事&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;Ollama Pro(0120)のサブスクリプションの累積に関する記事&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ol&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;これらの4つの記事のうち、3つは Knowledge Graph と &amp;lt;strong&amp;gt;全く&amp;lt;/strong&amp;gt; 関係がない。 彼らはそこにいる理由は、彼らが最も新しく公開されたものだからだ — 時間的近接ではない 意味的近傍。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;私はテンプレートを見ています`post.thyme`&amp;amp;lt;/think&amp;amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-xhtml hljs&amp;quot; data-lang=&amp;quot;xhtml&amp;quot;&amp;gt;&amp;amp;lt;!-- Articles connexes (liens internes SEO) --&amp;amp;gt;
&amp;amp;lt;th:block th:each=&amp;quot;post,postStat : ${published_posts}&amp;quot;&amp;amp;gt;
    &amp;amp;lt;th:block th:if=&amp;quot;${!post.uri.equals(content.uri) and postStat.index lt 4}&amp;quot;&amp;amp;gt;
        ...
    &amp;amp;lt;/th:block&amp;amp;gt;
&amp;amp;lt;/th:block&amp;amp;gt;&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;`published_posts`時系列のリストです。`postStat.index lt 4`取る 現在の投稿ではない最初の4つです。それだけです。ロジックはありません。 類似性。内容の概念はない。ただのループ`for`として仮装されている 推奨。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;admonitionblock warning&amp;quot;&amp;gt;
&amp;lt;table&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;icon&amp;quot;&amp;gt;
&amp;lt;i class=&amp;quot;fa icon-warning&amp;quot; title=&amp;quot;⚠️&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;
&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;JBakeのバグではありません。これはすべてのデフォルトの動作です。 静的サイトジェネレータ：投稿のリストはフラットで、日付順に並んでいる。 テンプレートは持っているものでできることをする。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/table&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;しかし、それを受け入れる理由ではない。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_診断テンプレートが見逃す３つの関係のタイプ&amp;quot;&amp;gt;診断：テンプレートが見逃す３つの関係のタイプ&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;私の記事コーパス — 4か月で23件の投稿 — は豊かな構造を持っている 時系列テンプレートは完全に上書きします：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;olist arabic&amp;quot;&amp;gt;
&amp;lt;ol class=&amp;quot;arabic&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;明示的な参照&amp;lt;/strong&amp;gt; : 使っています`xref:`私の記事で大量に。&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ol&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;記事 0122 参照 0106 (ナレッジグラフ) および 0116 (区画) 認識論的)。 これらのリンクは編集による*hard linking*です — 私は 故意にこれらの概念を接続することを決めた。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;olist arabic&amp;quot;&amp;gt;
&amp;lt;ol class=&amp;quot;arabic&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;共有タグ&amp;lt;/strong&amp;gt;: 各記事には`:jbake-tags:`. 記事について&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ol&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;Graphify + PlantUML (0105) a`gradle, graphify, plantuml, knowledge-graph`. Knowledge Graph (0106)の記事は &amp;lt;code&amp;gt;knowledge-graph, graphify, plantuml&amp;lt;/code&amp;gt;. 7つのうち3つのタグが共通 — 43％の重複率。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;olist arabic&amp;quot;&amp;gt;
&amp;lt;ol class=&amp;quot;arabic&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;共起する固有名詞&amp;lt;/strong&amp;gt; : « pgvector », « RAG », « embedding&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ol&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;4つの異なる記事に共同で現れる。 « LangChain4j »,  Ollama », « plugin Gradle » は他の六つにあります。これらはタグではありません。 宣言された — これらは*patterns émergents*のコーパスで、ただNLPだけが 検出できる。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
skinparam backgroundColor #FEFEFE
skinparam defaultTextAlignment center

title 記事間の関係の3層
package &amp;quot;層 1 — 明示的な参照&amp;quot; #CCFFCC {
    [Article A] as A1
    [Article B] as B1
    A1 -down-&amp;amp;gt; B1 : xref:
    note right of A1
        Liens durs
        Déterministes
        Déjà dans graph.json
    end note
}

package &amp;quot;レイヤー 2 — 共有タグ&amp;quot; #FFFFCC {
    [Article A] as A2
    [Article C] as C2
    A2 ..&amp;amp;gt; C2 : tag_cooccurrence
    note right of A2
        Poids = tags communs / tags totaux
        Déterministes
        À extraire via graphify
    end note
}

package &amp;quot;層3 — エマージェントオントロジー&amp;quot; #FFCCCC {
    [Corpus A] as A3
    [Corpus B] as B3
    A3 ..&amp;amp;gt; B3 : entity_overlap
    note right of A3
        Clusters NLP
        Co-occurrences d&amp;#39;entités nommées
        TF-IDF / cosine similarity
    end note
}

@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;今日、私のサイトはこれらの三つの層の*いずれも*使っていない。それは使う ゼロ層: Javaリストにおける挿入順序&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_解決策gradle_パイプラインホットな_llm_呼び出しではない&amp;quot;&amp;gt;解決策：Gradle パイプライン、ホットな LLM 呼び出しではない&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;最初の誘惑は、bakeの瞬間にLLMを呼び出すことでしょう：「Pour この記事は、コーパスの中で最も類似している3つの記事を見つける。  それをしないでください。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;admonitionblock important&amp;quot;&amp;gt;
&amp;lt;table&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;icon&amp;quot;&amp;gt;
&amp;lt;i class=&amp;quot;fa icon-important&amp;quot; title=&amp;quot;❗&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;
&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;各回のLLM呼び出し`./gradlew bake`時間とお金がかかり、 ビルドに非決定性を導入します。LLMの応答は 内容が変わらないまま、二つのビルド間を切り替える。あなたのCIが変化する。 再現できないため、あなたのテストは不安定になります。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/table&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;解決策は決定論的です：事前にグラフを計算するGradleパイプライン 類似性があり、それを保存します`graph.json`. テンプレートは結果を読み取ります — 彼は決して計算を開始しない。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_アーキテクチャ_bakeryはgraphifyをインポートしエンジンはインポートしない&amp;quot;&amp;gt;アーキテクチャ : BakeryはGraphifyをインポートし、エンジンはインポートしない&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;これは建築における最も重要な点です。 誘惑は…することになるだろう コラボレーションをケーブルする中で`engine/build.gradle.kts`：engine適用する スキャン用にgraphify、ベイク用にbakery、そしてエンジンがその間をつなぐ 両方。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;これはアンチパターンです。Engine は &amp;lt;strong&amp;gt;消費者端末&amp;lt;/strong&amp;gt; — それは適用する プラグインに関するビジネスロジックは実装していません。ルールは： &amp;lt;strong&amp;gt;�証明の責任はプロプライエタリなプラグインにあります。&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;正しいアーキテクチャ — Bakery は Graphify をインポートする&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
skinparam backgroundColor #FEFEFE
skinparam packageBackgroundColor #FFF3CD

title Bakery が Graphify をインポートします — Engine は何も知りません
package &amp;quot;N3 — エンジン&amp;quot; #FFCCCC {
    [engine/build.gradle.kts] as ENG
    note right of ENG
        plugins { bakery }
        Zéro connaissance de graphify
        4 tâches, ~150 lignes
    end note
}

package &amp;quot;N2 — ベーカリー&amp;quot; #CCFFCC {
    [bakery-plugin] as BAK
    note right of BAK
        plugins { graphify } ← import interne
        Lit graph.json
        Résout articles connexes
        Expose le modèle à JBake
    end note
}

package &amp;quot;N0 — GRAPHIFY&amp;quot; #CCE5FF {
    [graphify-plugin] as GRF
    note right of GRF
        Scan workspace → graph.json
        Enrichi avec :
        - xref: edges
        - co-occurrences de tags
        - entités nommées (NLP)
    end note
}

ENG -down-&amp;amp;gt; BAK : &amp;quot;プラグイン { ベーカリー }&amp;quot;
BAK -down-&amp;amp;gt; GRF : &amp;quot;プラグイン { グラフィファイ } ← N2→N0 オーケー&amp;quot;
@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;DAG契約は守られています：bakery (N2) が graphify (N0) をインポートしています、N2 &amp;amp;gt; N0, 違反はありません。エンジン (N3) はベーカリー (N2) をインポートします。N3 &amp;amp;gt; N2、OK。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;Engineには参照するコードの行が*ひとつも*ありません`graph.json`, &amp;lt;code&amp;gt;relatedPosts&amp;lt;/code&amp;gt;, または他の類似性の概念も。 彼はbakeryを適用する、点。 その コラボレーションはベーカリー内部です。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_パイプライン_スキャン_グラフ_テンプレート&amp;quot;&amp;gt;パイプライン: スキャン → グラフ → テンプレート&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;以下は3段階の完全なパイプラインです：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;olist arabic&amp;quot;&amp;gt;
&amp;lt;ol class=&amp;quot;arabic&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;スキャン&amp;lt;/strong&amp;gt; (グラフ化) :`graphify-plugin`ワークスペースをスキャンします。彼/彼女の&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ol&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;現在の形、すでにそれらを検出している`xref:`の間`.adoc`そして ～にさらす`graph.json`タイプのedgesのような`reference`.&amp;lt;br&amp;gt;
私たちはそれを編集コンテンツのために豊かにします： * JBakeのメタデータを解析 (&amp;lt;code&amp;gt;:jbake-tags:&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;:jbake-description:&amp;lt;/code&amp;gt;) それぞれの`.adoc`ブログの * タグの共起を計算 → edges`tag_cooccurrence`重さとともに * 名前付きエンティティをTF-IDFを使って説明から抽出 → エッジ`entity_overlap` セクションを注入する`blog_articles`の中`graph.json`存在する&amp;lt;br&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-kotlin hljs&amp;quot; data-lang=&amp;quot;kotlin&amp;quot;&amp;gt;// Extrait de l&amp;#39;enrichissement graphify pour le blog
fun enrichBlogSection(graphJson: File, blogDir: File): GraphJson {
    val articles = blogDir.listFiles { f -&amp;amp;gt; f.extension == &amp;quot;adoc&amp;quot; }
        .map { parseJbakeMetadata(it) }

    val nodes = articles.map { ArticleNode(it.slug, it.title, it.tags) }
    val edges = mutableListOf&amp;amp;lt;GraphEdge&amp;amp;gt;()

    // Couche 1 : xref (déjà fait par scanWorkspace)

    // Couche 2 : co-occurrences de tags
    for (a in articles) {
        for (b in articles) {
            if (a.slug == b.slug) continue
            val common = a.tags.intersect(b.tags)
            if (common.isNotEmpty()) {
                edges.add(GraphEdge(
                    source = a.slug,
                    target = b.slug,
                    type = &amp;quot;tag_cooccurrence&amp;quot;,
                    weight = common.size.toDouble() / (a.tags.size + b.tags.size)
                ))
            }
        }
    }

    return graphJson.copy(
        blogArticles = BlogSection(nodes, edges)
    )
}&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;olist arabic&amp;quot;&amp;gt;
&amp;lt;ol class=&amp;quot;arabic&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;Bake&amp;lt;/strong&amp;gt; (bakery) : その瞬間の`./gradlew bake`, `BakeryPlugin`ベッド&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ol&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;`graph.json`そして関連記事を各投稿ごとに解決します。&amp;lt;br&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-kotlin hljs&amp;quot; data-lang=&amp;quot;kotlin&amp;quot;&amp;gt;// BakeryPlugin — résolution des articles connexes
fun resolveRelatedPosts(
    currentSlug: String,
    graph: GraphJson,
    maxResults: Int = 4
): List&amp;amp;lt;RelatedPost&amp;amp;gt; {
    val edges = graph.blogArticles.edges
        .filter { it.source == currentSlug || it.target == currentSlug }

    return edges
        .sortedByDescending { it.weight }
        .take(maxResults)
        .map { edge -&amp;amp;gt;
            val relatedSlug = if (edge.source == currentSlug) edge.target else edge.source
            graph.blogArticles.nodes.first { it.slug == relatedSlug }
        }
}&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;olist arabic&amp;quot;&amp;gt;
&amp;lt;ol class=&amp;quot;arabic&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;Template&amp;lt;/strong&amp;gt; (&amp;lt;code&amp;gt;post.thyme&amp;lt;/code&amp;gt;) : JBakeモデルは現在、Mapを受け取ります&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ol&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;平坦な時系列リストではなく、構造化されたもの。&amp;lt;br&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-xhtml hljs&amp;quot; data-lang=&amp;quot;xhtml&amp;quot;&amp;gt;&amp;amp;lt;!-- Articles connexes basés sur le Knowledge Graph --&amp;amp;gt;
&amp;amp;lt;th:block th:if=&amp;quot;${relatedPosts != null and !relatedPosts.empty}&amp;quot;&amp;amp;gt;
    &amp;amp;lt;section class=&amp;quot;mt-5 pt-4 border-top&amp;quot;&amp;amp;gt;
        &amp;amp;lt;h2 class=&amp;quot;h4 mb-3&amp;quot;&amp;amp;gt;Articles connexes&amp;amp;lt;/h2&amp;amp;gt;
        &amp;amp;lt;th:block th:each=&amp;quot;related : ${relatedPosts}&amp;quot;&amp;amp;gt;
            &amp;amp;lt;div class=&amp;quot;mb-2&amp;quot;&amp;amp;gt;
                &amp;amp;lt;a th:href=&amp;quot;${content.rootpath} + ${related.uri}&amp;quot;
                   th:text=&amp;quot;${related.title}&amp;quot; class=&amp;quot;fw-semibold&amp;quot;&amp;amp;gt;&amp;amp;lt;/a&amp;amp;gt;
                &amp;amp;lt;br/&amp;amp;gt;
                &amp;amp;lt;small class=&amp;quot;text-muted&amp;quot;&amp;amp;gt;
                    &amp;amp;lt;th:block th:each=&amp;quot;reason,iterStat : ${related.reasons}&amp;quot;&amp;amp;gt;
                        &amp;amp;lt;span class=&amp;quot;badge bg-light text-dark&amp;quot;
                              th:text=&amp;quot;${reason}&amp;quot;&amp;amp;gt;&amp;amp;lt;/span&amp;amp;gt;
                    &amp;amp;lt;/th:block&amp;amp;gt;
                &amp;amp;lt;/small&amp;amp;gt;
            &amp;amp;lt;/div&amp;amp;gt;
        &amp;amp;lt;/th:block&amp;amp;gt;
    &amp;amp;lt;/section&amp;amp;gt;
&amp;amp;lt;/th:block&amp;amp;gt;&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;テンプレートは同じです — それはデータがどこから来たかを知りません。 ベーカリーとJBakeの間の契約だけが変更されました：&amp;lt;code&amp;gt;published_posts&amp;lt;/code&amp;gt;(リスト 時系列) なる`relatedPosts`(グラフによる重み付けマップ)&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;admonitionblock note&amp;quot;&amp;gt;
&amp;lt;table&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;icon&amp;quot;&amp;gt;
&amp;lt;i class=&amp;quot;fa icon-note&amp;quot; title=&amp;quot;ℹ️&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;
&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;「理由」バッジ（例：&amp;lt;code&amp;gt;xref 0122&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;tag:gradle&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;cluster:pgvector-rag&amp;lt;/code&amp;gt;) 読者に説明します &amp;lt;strong&amp;gt;pourquoi&amp;lt;/strong&amp;gt; この記事は関連しています。これは～ではない 透明性だけ — それはトポロジーの教育法だ あなた独自のコンテンツ。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/table&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_クロノロジカルフォールバック&amp;quot;&amp;gt;クロノロジカルフォールバック&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;Si `graph.json`存在しない（ローカルビルド、事前スキャンなし、最初） デプロイ, CIはまだスキャン グラフファイ), テンプレート 優雅に劣化しなければならない：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-kotlin hljs&amp;quot; data-lang=&amp;quot;kotlin&amp;quot;&amp;gt;fun resolveRelatedPosts(currentSlug: String, graph: GraphJson?): List&amp;amp;lt;RelatedPost&amp;amp;gt; {
    if (graph != null &amp;amp;amp;&amp;amp;amp; graph.blogArticles != null) {
        return resolveFromGraph(currentSlug, graph)
    }
    // Fallback chronologique — même comportement qu&amp;#39;aujourd&amp;#39;hui
    logger.warn(&amp;quot;[bakery] graph.json absent — fallback chronologique&amp;quot;)
    return resolveFromChronology(currentSlug)
}&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;デフォルトの動作は現在の動作と同じです。その レコメンデーションエンジンは、&amp;lt;strong&amp;gt;段階的な改善&amp;lt;/strong&amp;gt; — ではない ブレイキング・チェンジ。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_エマージェントオントロジー_記事が互いを知らずに集まるとき&amp;quot;&amp;gt;エマージェントオントロジー : 記事が互いを知らずに集まるとき&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;最も興味深い層は第三層：新興オントロジーです。 引用されない記事で、同じタグを持たないものだが 同じことを話している人は、それに気づいていない。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;具体的な例を挙げましょう。 私のコーパスから3つの記事：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;olist arabic&amp;quot;&amp;gt;
&amp;lt;ol class=&amp;quot;arabic&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;0119 — ベンチマーク DGX Spark 対 クラウド サブスクリプション LLM&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;0121 — Gradle プラグイン Ollama Pro 2 インスタンスを操作&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;0122 — 効率比 27x 45x IAエキスパートフリート&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ol&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;これらの3つの記事には、&amp;lt;strong&amp;gt;aucun&amp;lt;/strong&amp;gt; xref がありません。彼らのタグは 彼らは20％しかカバーしていません（「ollama」、「llm」が共通です）。しかし軽量な NLP です。 説明について明らかなクラスターが示される：« コスト », « サブスクリプション »,  クラウド », « GPU », « APIキー », « Ollama Pro », « 効率 », « 比率&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;彼らはオントロジー的クラスターを形成します：&amp;lt;strong&amp;gt;LLMセルフホストドの経済 vs cloud&amp;lt;/strong&amp;gt; このクラスターはどこにも宣言されていません。コーパスから現れます。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
skinparam backgroundColor #FEFEFE
skinparam packageBackgroundColor #E8F8F5

title Cluster Ontologique Émergent — &amp;quot;LLMセルフホステッド経済&amp;quot;

package &amp;quot;クラスター検出 : 経済-LLM&amp;quot; #D5F5E3 {
    [0119 — Benchmark DGX Spark\nvs Cloud Abonnement] as A
    [0121 — Plugin Gradle Piloter\nDeux Instances Ollama Pro] as B
    [0122 — Ratio Efficacité\n27x 45x Flotte Experts] as C
}

A .. B : entity_overlap (0.73)
B .. C : entity_overlap (0.81)
A .. C : entity_overlap (0.68)

note bottom of A
    Aucun xref entre ces articles.
    Tags communs : &amp;quot;オラマ&amp;quot;, &amp;quot;llm&amp;quot;.
    Cluster découvert par NLP :
    co-occurrences &amp;quot;コスト&amp;quot;, &amp;quot;GPU&amp;quot;,
    &amp;quot;サブスクリプション&amp;quot;, &amp;quot;オラマ プロ&amp;quot;.
end note
@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;このオントロジークラスターは複合エッジになります。&amp;lt;code&amp;gt;graph.json&amp;lt;/code&amp;gt;:&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-json hljs&amp;quot; data-lang=&amp;quot;json&amp;quot;&amp;gt;{
  &amp;quot;source&amp;quot;: &amp;quot;0119-benchmark-dgx-spark&amp;quot;,
  &amp;quot;target&amp;quot;: &amp;quot;cluster:economie-llm&amp;quot;,
  &amp;quot;type&amp;quot;: &amp;quot;entity_cluster&amp;quot;,
  &amp;quot;weight&amp;quot;: 0.73,
  &amp;quot;metadata&amp;quot;: {
    &amp;quot;clusterLabel&amp;quot;: &amp;quot;Économie LLM Self-Hosted vs Cloud&amp;quot;,
    &amp;quot;commonEntities&amp;quot;: [&amp;quot;coût&amp;quot;, &amp;quot;GPU&amp;quot;, &amp;quot;abonnement&amp;quot;, &amp;quot;Ollama Pro&amp;quot;, &amp;quot;ratio&amp;quot;],
    &amp;quot;articlesInCluster&amp;quot;: [
      &amp;quot;0119-benchmark-dgx-spark&amp;quot;,
      &amp;quot;0121-ollama-pro-deux-instances&amp;quot;,
      &amp;quot;0122-ratio-efficacite-flotte-experts&amp;quot;
    ]
  }
}&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;NLPは意図的に軽量です — TF-IDF + コサイン類似度（sur les） 説明。BERTは必要ありません、言語モデルは必要ありません。 コーパスは23件の記事で構成されており、類似度行列は1つに収まります 50 KoのJSONファイル。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;admonitionblock tip&amp;quot;&amp;gt;
&amp;lt;table&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;icon&amp;quot;&amp;gt;
&amp;lt;i class=&amp;quot;fa icon-tip&amp;quot; title=&amp;quot;💡&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;
&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;NLPの力は、アルゴリズムの高度さから来なくて しかし、*コーパスのサイズ*と*説明の品質*によるものです。 一つ `:jbake-description:`よく書かれた150文字はもっと含んでいる TF-IDFに、3000語の記事全体であることを示す信号。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/table&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_dag契約誰が誰に重要か&amp;quot;&amp;gt;DAG契約：誰が誰に重要か&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;これは建築の規律が報われる点です。DAG N0→N3 で定義されている`engine/build.gradle.kts`簡単なルールを与える： どのプロジェクトも上位のプロジェクトとは関係ない。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;table class=&amp;quot;tableblock frame-all grid-all stretch&amp;quot;&amp;gt;
&amp;lt;colgroup&amp;gt;
&amp;lt;col style=&amp;quot;width: 18.1818%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 18.1818%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 18.1818%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 18.1818%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 27.2728%;&amp;quot;&amp;gt;
&amp;lt;/colgroup&amp;gt;
&amp;lt;thead&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;th class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;コンシューマープラグイン&amp;lt;/th&amp;gt;
&amp;lt;th class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;インポートされたプラグイン&amp;lt;/th&amp;gt;
&amp;lt;th class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;消費者レベル&amp;lt;/th&amp;gt;
&amp;lt;th class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;インポートされたレベル&amp;lt;/th&amp;gt;
&amp;lt;th class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;有効ですか？&amp;lt;/th&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/thead&amp;gt;
&amp;lt;tbody&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;bakery-gradle&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;graphify-gradle&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;N2&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;N0&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;✅ N2 &amp;amp;gt; N0 — OK&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;エンジン&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;bakery-gradle&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;N3&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;N2&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;✅ N3 &amp;amp;gt; N2 — OK&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;エンジン&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;graphify-gradle&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;N3&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;N0&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;�✅ 技術 OK, しかし &amp;lt;strong&amp;gt;概念的に間違っている&amp;lt;/strong&amp;gt; — コラボレーションはbakery内部にある&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/tbody&amp;gt;
&amp;lt;/table&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;Engine 適用する bakery. Bakery 適用する graphify. それだけです。ある日 ベクトルストアコードベース (N1) を研究のために追加したいです。 クロス・コーパスの意味解析、ベーカリーもインポートします。Engineは変わりません。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;admonitionblock important&amp;quot;&amp;gt;
&amp;lt;table&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;icon&amp;quot;&amp;gt;
&amp;lt;i class=&amp;quot;fa icon-important&amp;quot; title=&amp;quot;❗&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;
&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;パターンは：&amp;lt;strong&amp;gt;プラグイン N2 は自身の依存関係のハブです&amp;lt;/strong&amp;gt;。 エンジンN3はハブではありません―それはハブを適用するターミナル。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/table&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_得られることと得られないこと&amp;quot;&amp;gt;得られることと得られないこと&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;主な利益は編集的で、技術的ではない：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;table class=&amp;quot;tableblock frame-all grid-all stretch&amp;quot;&amp;gt;
&amp;lt;colgroup&amp;gt;
&amp;lt;col style=&amp;quot;width: 50%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 50%;&amp;quot;&amp;gt;
&amp;lt;/colgroup&amp;gt;
&amp;lt;thead&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;th class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;前に&amp;lt;/th&amp;gt;
&amp;lt;th class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;後&amp;lt;/th&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/thead&amp;gt;
&amp;lt;tbody&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;関連記事 = 最新4件の投稿&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;関連記事 = Knowledge Graph での重み上位 4件&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;読み手はRAGを読む → Kitty Terminalの推奨&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;リーダーが RAG を読む → pgvector、チャンク化、ベクターストアの推奨&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;なぜについての透明性はゼロ&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;バッジ`xref 0122`, &amp;lt;code&amp;gt;tag:gradle&amp;lt;/code&amp;gt;, `cluster:rag`見える&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;JBake標準、ゼロ労力、ゼロ価値&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;決定的、再現可能、テスト可能なグレードルパイプライン&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;読者に学習曲線はありません&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;読者は私のコンテンツの*トポロジー*を発見する&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/tbody&amp;gt;
&amp;lt;/table&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;得られないもの：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;これは « 本当の » レコメンデーション エンジンではない (コラボラティブ&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;filtering,A/B testingなし,feedback loopなし)&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;品質はJBakeのメタデータの豊富さに依存します — もしあなたの&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;説明は空です、TF-IDFは何も見ません&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;NLPはオフラインです — 新しい記事はただクラスター化されているだけです&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;次のスキャン (いいね：ビルドは依然として決定的です)&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_視点パブリックナレッジグラフとしてのブログ&amp;quot;&amp;gt;視点：パブリックナレッジグラフとしてのブログ&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;この機能はより広い視点を開く：もし～なら`cheroliv.com` 彼は自分自身が*ナビゲータブルな知識グラフ*になったのか？&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;記事はノードです。タグはコミュニティです。xrefは �辺。読者はもはや孤立した記事を読まず — 彼は～の中をナビゲートする &amp;lt;strong&amp;gt;知識グラフ&amp;lt;/strong&amp;gt; 現在の記事がエントリーポイントです。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;時系列のリストを表示しないホームページを想像してください 最新の投稿だが、&amp;lt;strong&amp;gt;コーパスマップ&amp;lt;/strong&amp;gt;：オントロジーのクラスター, ピボット記事（エッジが最も多いもの）, 読み取りパス おすすめ「もしGraphifyの記事が気に入ったら、次に読んでください Knowledge Graphを理解するためのツールとしてのもの&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;これはもうブログではない。これは*セマンティックアトラス*です。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;そしてこれはSFではありません。その`graph.json`既に存在しています。 彼に欠けているのはナビゲーションインターフェースだけだ。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_結論ファイルシステムはテンプレートが無視するものを知っている&amp;quot;&amp;gt;結論：ファイルシステムはテンプレートが無視するものを知っている&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;私が火曜日の夜に考案したのは、ヒューリスティックの置き換えです。 怠惰な（年代順）による忠実な表現の 私のコーパスの構造 (Knowledge Graph)。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;テンプレート`post.thyme`変わらない。変わるのは、私たちが 彼に食べ物を与える。 前 : 並び替えられた Java リスト`date`. 後： 3つの解析層から導出された重み付きグラフ — xrefs, 共起 タグ、およびNLPによる新興オントロジー&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;ループが閉じられました。 graphifyはワークスペースをスキャンします。 Bakeryは グラフとテンプレートを埋める。 読者はおすすめを見る そしてエンジン — 指揮者 — はそれについてさえ知らないと それらはすべて存在する。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;これで正しいアーキテクチャです。各プラグインは一つのことだけを行います。 消費者端末はどのようにするかを知る必要はありません。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_参照&amp;quot;&amp;gt;参照&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;0105_integrer_graphify_workflow_gradle_post.html&amp;quot;&amp;gt;Article 0105 — GraphifyをGradleワークフローに組み込む&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;0106_knowledge_graph_outil_comprehension_codebase_post.html&amp;quot;&amp;gt;記事0106 — ナレッジグラフを理解のためのツールとして&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;記事0117 — OSS/CSSの細分化&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;0121_plugin_gradle_piloter_deux_instances_ollama_pro_post.html&amp;quot;&amp;gt;記事 0121 — Gradle プラグイン Ollama Pro の 2 インスタンスを操作&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;0122_ratio_efficacite_27x_45x_flotte_experts_ia_vs_claude_gpt_post.html&amp;quot;&amp;gt;Article 0122 — 27× から 45× より効率的 : AIエキスパートフリート&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;</description>
        </item><item>
            <title>27倍から45倍、ClaudeとGPTより効率的：23人のファインチューニングされたAIエキスパートの艦隊が市場を制する方法</title>
            <link >https://cheroliv.com/blog/2026/0122_ratio_efficacite_27x_45x_flotte_experts_ia_vs_claude_gpt_post.html</link>
            <pubDate>Mon, 11 May 2026 00:00:00 +0000</pubDate>
            <guid isPermaLink="false">blog/2026/0122_ratio_efficacite_27x_45x_flotte_experts_ia_vs_claude_gpt_post.html</guid>
            <description>&amp;lt;div id=&amp;quot;toc&amp;quot; class=&amp;quot;toc&amp;quot;&amp;gt;
&amp;lt;div id=&amp;quot;toctitle&amp;quot;&amp;gt;Table des matières&amp;lt;/div&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel1&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_問題なぜファインチューンではなくragを使わないのか&amp;quot;&amp;gt;問題：なぜファインチューンではなくRAGを使わないのか？&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_考え_専門家の艦隊単一のモデルではない&amp;quot;&amp;gt;考え: 専門家の艦隊、単一のモデルではない&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_拡大鏡で見たコードベース_7_900_ファイル144_000_行&amp;quot;&amp;gt;�拡大鏡で見たコードベース : 7 900 ファイル、144 000 行&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div id=&amp;quot;preamble&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;読了時間 : 22 minutes&amp;lt;/div&amp;gt;
&amp;lt;p&amp;gt;日常的にソフトウェア開発でLLMを使うと、いつも同じ壁にぶつかることになります：モデルは*あなたの*コードベースを知りません。それはあなたがそのようなパターンを使っていることを知らないhttps://fr.wikipedia.org/wiki/Graphe_orient%C3%A9_acyclique[DAG], そのような Gradle の慣習, そのような認識論的層構造 あなたのhttps://fr.wikipedia.org/wiki/AsciiDoc[.adoc]. それから彼にコンテキストを注入し、繰り返し、修正し、反復する。そして時間―そしてお金―が過ぎていく。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;だから私は率直に質問した：私のワークスペースでファインチューニングされたモデルのチームを作るにはどれくらいのコストがかかるだろうか、*私のスタイル*でコードを出力でき、毎回説明する必要なく動くチームは。特に：このアプローチは、Claude、GPT、Gemini、Grokなどの従来の propietary ソリューションとどう比べられるだろうか？&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;返答に驚いた。私が想像していたよりもはるかに少なかった。そして、業界の巨人たちと比較したコストパフォーマンスの比率はとんでもない。詳細は以下の通りです。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_問題なぜファインチューンではなくragを使わないのか&amp;quot;&amp;gt;問題：なぜファインチューンではなくRAGを使わないのか？&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;RAGは良いです。&amp;lt;a href=&amp;quot;0106_knowledge_graph_outil_comprehension_codebase_post.html&amp;quot;&amp;gt;私のナレッジグラフ&amp;lt;/a&amp;gt;と&amp;lt;a href=&amp;quot;0116_compartimentage_epistemique_automatise_llm_post.html&amp;quot;&amp;gt;私の認識の区画化&amp;lt;/a&amp;gt;は機能しています。しかし、RAGには根本的な欠点があります：各クエリごとに、関連するコンテキストを再注入しなければなりません。あなたのプロンプトは伸び、遅延は爆発し、モデルは決してあなたのパターンを*内面化*せず—常に外部のドキュメントとして読み取ります。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;ファインチューンこそが筋肉の記憶です。モデルは*知っている*が、君は書いている`build.gradle.kts`記録されたタスクを介して`tasks.register`, あなたの`AGENTS.adoc`標準的な構文に従い、あなたのワークスペースはboroughsに構造化されている。彼には思い出させる必要はない。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;admonitionblock note&amp;quot;&amp;gt;
&amp;lt;table&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;icon&amp;quot;&amp;gt;
&amp;lt;i class=&amp;quot;fa icon-note&amp;quot; title=&amp;quot;ℹ️&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;
&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;ファインチューニングはRAGの代替ではありません。これは補完的なレイヤーです。RAGは頻繁に変化するデータ（ログ、チケット、最近のコミットなど）に対して依然として関連があります。ファインチューニングは長期的な構造的かつスタイル的な知識のために用いられます。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/table&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_考え_専門家の艦隊単一のモデルではない&amp;quot;&amp;gt;考え: 専門家の艦隊、単一のモデルではない&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;ワークスペース全体に対して1つだけファインチューニングされたモデルでもそれはまあまあ良いです。しかしそれは最適ではありません。私のワークスペースは非常に異なる分野をカバーしています ：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;Gradleプラグイン(Kotlin、規約プラグイン、複合ビルド)&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;DAGエンジン (Kotlin, スケジューリング, 実行)&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;LLMエージェント (Python, LangChain4j, RAG)&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;アーキテクチャドキュメント (AsciiDoc, ガバナンス)&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;インフラ/DevOps（Docker、GitHub Actions、CI/CD）&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;単一のモデルはどこでもそれなりに良いが、どこでも優れているわけではない。解決策？一つ&amp;lt;strong&amp;gt;専門モデルの艦隊&amp;lt;/strong&amp;gt;、オーケストレーターが各リクエストを適切なエキスパートにルーティングします&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
skinparam backgroundColor #FAFAFA
skinparam defaultFontSize 13

package &amp;quot;Ollama クラウド&amp;quot; {
  rectangle &amp;quot;DeepSeek V4-Pro
1.6T / 49B 資産&amp;quot; as V4Pro #FF6B6B
  rectangle &amp;quot;6× V4-Flash-FT
292B / 13B 資産&amp;quot; as Flash #4ECDC4
  rectangle &amp;quot;6× Gemma4 26B-FT\n26B / 3.8B アクティブ&amp;quot; as Gemma #FFE66D
  rectangle &amp;quot;5× Qwen3.6 35B-FT
35B / 3B アクティブ&amp;quot; as Qwen36 #A8E6CF
  rectangle &amp;quot;5× Qwen3.5 35B-FT\n35B / 3B アクティブ&amp;quot; as Qwen35 #FF8B94
}

note bottom of Qwen35
  À partir de 17€/mois
  (1× Ollama Pro annual)
  Extensible par cumul
  de comptes Pro selon
  la méthode Docker.
end note

actor Utilisateur as User

User --&amp;amp;gt; V4Pro : Requête
V4Pro --&amp;amp;gt; Flash : &amp;quot;複雑なGradleタスク&amp;quot;
V4Pro --&amp;amp;gt; Gemma : &amp;quot;AsciiDoc のフォーマット&amp;quot;
V4Pro --&amp;amp;gt; Qwen36 : &amp;quot;Kotlinのリファクタリング&amp;quot;
V4Pro --&amp;amp;gt; Qwen35 : &amp;quot;Bashスクリプト&amp;quot;

note right of V4Pro
  L&amp;#39;orkestrateur route
  la requête vers l&amp;#39;expert
  le plus pertinent.
  Zéro prompt engineering
  répétitif.
end note

@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;総艦隊：&amp;lt;strong&amp;gt;1 オーケストレータ + 22 エキスパート = 23 モデル&amp;lt;/strong&amp;gt;そして、月間の推論コストはいくらですか？&amp;lt;strong&amp;gt;17ユーロ/月&amp;lt;/strong&amp;gt;Ollama Pro年間サブスクリプション — クォータを超過した場合はアカウントの累積により拡張可能で、これは &amp;lt;a href=&amp;quot;0120_cumuler_deux_abonnements_ollama_pro_docker_post.html&amp;quot;&amp;gt;Dockerマルチアカウント方法&amp;lt;/a&amp;gt; で示されています。基本料金は17ユーロからで、実際のニーズに応じて段階ごとに20ユーロずつ追加します。無駄はありません。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_拡大鏡で見たコードベース_7_900_ファイル144_000_行&amp;quot;&amp;gt;�拡大鏡で見たコードベース : 7 900 ファイル、144 000 行&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;トレーニングのコストを見積もる前に、何をトレーニングすべきかを知る必要があります。私は、Gitによって無視されるものを厳密に除外して、ワークスペースを監査しました。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-none hljs&amp;quot;&amp;gt;----
----
build/    out/    node_modules/    runtimes/    .gradle/    dist/
target/   venv/   __pycache__/     .cache/      .tox/
----

以下は、追跡されているファイルのみの結果です：

[cols=&amp;quot;2,2&amp;quot;]
|===
|メトリック |値

|追跡されたソースファイル |**7 896** |コード行数(LOC) |**百四十三千八百五** |Git リポジトリ |**二十六** |主要な言語 |Kotlin (1 903), AsciiDoc (2 765), Python (5 029)
|===

[IMPORTANT]
====
これらの5,000+のPythonファイルには`runtimes/`ノートブックとユーティリティスクリプト。アプリケーションのコア（Gradleプラグイン、DAGエンジン、エージェント）は主にKotlinとAsciiDocで書かれています。
====

私はこの質量から合成データセットを生成できると推定します**約1億7000万トークン**インストラクターLLMを経由して (コードベースを命令/応答ペアに蒸留する).

=== 専門家タイプ別のデータセットの詳細

[source,text]
----
Dataset maître (généraliste V4-Flash) :    50M tokens
Expert Gradle/Build        :    15M tokens
Expert Kotlin/DAG          :    15M tokens
Expert AsciiDoc/Gouvernance:    15M tokens
Expert Agent/LLM/Python    :    15M tokens
Expert Infra/CI-CD         :    15M tokens
Micro-experts Qwen/Gemma   :   ~5M tokens chacun
----

== モデルの選択 : 100% MoE, ゼロ dense

そこに建築が本当に効率的になります。

*dense* モデルは、各トークンで全ての重みをアクティベートします。*MoE* (Mixture of Experts) モデルは、そのパラメータの一部のみをアクティベートします。推論およびファインチューニングのコストは、パラメータ数に比例します。**有効**, パラメータには適用されません**保存された**。

Ollama Cloudでは、今日市場がMoE向けに提供しているものを見てみましょう：

[cols=&amp;quot;3,2,2,1,3&amp;quot;]
|===
|モデル |総パラメータ数 |活性化された |活性化 |Ollama クラウド

|DeepSeek V4-Pro |1.6T |49B |3.1% |ネイティブ |ディープシーク V4-Flash |292B |13B |4.5% |�✅ ネイティブ |Gemma 4 26B-A4B |26B |38億 |14.6% |�✅ ネイティブ |Qwen3.6-35B-A3B |35B |3B |8.6% |❌ (まだ統合されていません) |Qwen3.5-35B-A3B |35B |3B |8.6% |�✅ ネイティブ
|�❌ Qwen3.5-27B |27B |27B |100%濃密 |排除された |❌ Qwen3.5-4B/9B |4B/9B |4B/9B |100％濃密 |除去された |�❌ Gemma 4 31B |31B |31B |100% 密集 |除去された
|�🧪 Gemma 4 E2B/E4B |5B/8B |5B/8B |100% 密集している |バリデーションパイプライン
|===

[CAUTION]
====
アクティベーション比率が判別基準です。Gemma 4 26B-A4Bは26Bのパラメータのうち3.8Bのみをアクティベートします — これは密な27Bの7倍少なく、コーディングエージェントの性能が同等です（LiveCodeBench v6で77.1%対80%）。
====

=== なぜ私が密なモデルをやめるのか

例外：Gemma 4 E2B と E4B。これらの2つのモデルは Apache 2.0 ライセンスで、コストを抑えてトレーニングパイプラインをテストおよび検証するのに最適です。E2B での 2-3 時間の実行は $5 未満のコストです。データセットまたはハイパーパラメータに問題がある場合、わずか数ドルでそれを知ることができます。パイプラインが整ったら、超マイクロタスク（単純な再フォーマット、二値分類）にも使用できます。しかし、メインフリートのエキスパートについては、私は MoE を使い続けます。なぜかというと：

。しかしそれだけじゃない：Gemma 4 E2B/E4Bは、細やかな匿名化の専門家だ

[NOTE]
====
Google はこれらの小さなモデルをネイティブなツール呼び出しにおいて競争力があるように設計しました — 彼らは関数を呼び出し、正規表現を操作し、パターンを検索することができます。匿名化の例（メール、トークン、UUID、ファイルパス）でファインチューニングすると、彼らは**データセットの匿名化ツール**超高速。 彼らは生テキストのブロックを与え、彼らは呼ぶ`sed`(No text to translate, so output empty)`regex`via ツールコール を呼び出し、クリーンなブロックを返却します。推論コストは微々たるものです：5B がアクティベートされ、エントリーレベルのシングル GPU で十分です。これらのモデルは業界の専門家ではありません — それらは**熟練労働者**データセットの生産チェーンの中
====

* そのトレーニング用VRAM（QLoRAでも）は、それに比例する**27B 合計**
* 彼のトレーニング時間は、に比例する**27B が有効**

Qwen3.6-35B-A3B (MoE) と比較してみましょう：

[cols=&amp;quot;3,2,2,2&amp;quot;]
|===
| |Qwen3.5-27B (dense) |Qwen3.6-35B-A3B (MoE) |比率

|VRAM QLoRA |~55 GB |~35 GB |1.6× |GPU時間 (8M トークン) |約12時 |約4時間 |**3×** |ファインチューンあたりのコスト |~$24 |~$8 |**3×** |SWE-bench Verified |75.0% |73.4% |比較可能
|===

MoEはエージェントコーディングの性能を5%程度で、訓練コストが3倍少なくなります。22人の専門家の間で、差額は数千ユーロに上ります。

== トレーニングの見積もり: 811 H100時間

QLoRA 4-bit でモデルごとのトレーニングコストを、前述のデータセットに基づいて内訳した。

=== �軽量なマイクロエキスパートMoE(3-3.8B活性化された)

これらのモデルは、実行ごとに H100 (80 GB) が 1 つ必要です。 Q4 のモデルの VRAM は約 13–18 GB であり、LoRA オプティマイザー状態およびアクティベーション用に十分な余裕があります。

[cols=&amp;quot;4,2,3,2&amp;quot;]
|===
|モデル |実行回数 |GPU時間/実行 |合計 GPU時間

|Gemma 4 26B-A4B-FT |6 |3.5 h |**21時** |Qwen3.6-35B-A3B-FT |5 |4.0 h |**20 時間** |Qwen3.5-35B-A3B-FT |5 |4.0 h |**20時** |マイクロ 小計 | | |*61 h*
|===

=== V4-Flash エグゼクティブ (13B 有効 / 292B 保存)

DeepSeek V4-Flashは特別なケースです。トークンあたり13Bしかアクティベートされませんが、Q4のフルモデルは約142 GBあります — トレーニング中はすべてのエキスパートがVRAMに存在する必要があります。したがって**3× H100**走ることによって快適になるため

[cols=&amp;quot;4,2,3,3,2&amp;quot;]
|===
|モデル |データセット |GPU |時間 |合計GPU時間

|V4-Flash-Base 汎用 |50M トク |3× H100 |50 h |**150 時間** |V4-Flash エキスパート ×5 |15M トークン |3× H100 |40 h |**600時間** |*幹部小計* | | | |*750 h*
|===

[cols=&amp;quot;3,2,1&amp;quot;]
|===
|**合計** | |**811 H100-h**
|===

[NOTE]
====
比較として、QLoRAなし（すべての重み）でV4-Flashをフルファインチューンすると、6モデルだけで約4 000 H100時間かかる。QLoRAはコストを5分の1に削減する。これがこの規模でプロジェクトを経済的に実行可能にする唯一の方法である。
====

=== GPUの料金：2026年5月に誰が何を借りているか

私は主要なH100レンタル業者をベンチマークしました。メーター価格、811時間分。

[cols=&amp;quot;3,2,2,2&amp;quot;]
|===
|�貸主 |$/H100·h |合計 811時間 |信頼性

|**Vast.ai スポット** |$1.60 |**$1,298** |★★☆ 中断可能 |**クルーソー クラウド** |$2.00 |**$1 622** |★★★★ 信頼できるデータセンター |FluidStack |$1.98 |$1 606 |★★★ |TensorDock |$1.80 |$1 460 |★★☆ |RunPod |$2.29 |$1 857 |★★★ 良い妥協 |CoreWeave |$2.25 |$1 825 |★★★★ 企業 |ラムダ・ラボ |$2.49 |$2 019 |★★★★ プレミアム
|===

[TIP]
====
Vast.ai のスポットは最も安いですが、実行はいつでも中断される可能性があります。トレーニングにはリスクがあります。Crusoe は $2.00/h で、信頼性と価格のバランスが最も良いです。Vast と比較した $324 の追加コストは、心の平穏に値します。
====

=== Wall-clock : すべてをトレーニングするのにどのくらい時間がかかりますか？

単一の3× H100ノードでは、31回の実行（汎用1 + エキスパート30）は約**12日間**シーケンシャルで。 もしノードを2つ並列で借りると、それに落ちる**6日**。

実際には、マイクロエキスパートは個別のノード（それぞれ1つのH100）で稼働し、その間にV4‑Flashが3×H100のノードを占有します。賢いスケジューリングを用いると：

----

Nœud A (3× H100) : V4-Flash généraliste → V4-Flash experts ×5       (11 jours) Nœud B (1× H100) : Gemma 4 26B ×6 → Qwen 36 ×5 → Qwen 35 ×5        (6 jours)

7日間のレンタル、すべて折りたたみ。

== 推論: Ollama Cloud で 23 のモデルが月額 17 ユーロから

これは建築で最もエレガントな部分です。

Ollama Cloud はプライベートモデルをアップロードすることができます（Pro プランの機能）。私の22個のファインチューニング済みモデルは、…にプッシュされます`.gguf`私の Ollama スペースで、プライベートとしてマークされ、標準 API を介してアクセス可能です。

[plantuml, inference-flow, svg]
----
@startuml
skinparam backgroundColor #FAFAFA
skinparam defaultFontSize 12

|Utilisateur|
start
:Tâche de développement;

|Orkestrateur (V4-Pro)|
:Classifier la tâche\n(domaine + complexité);
if (Tâche simple,\nspécialisée ?) then (oui)
  :Router vers micro-expert\n(Gemma 4 26B-A4B-FT\n ou Qwen3.6-35B-A3B-FT);
elseif (Tâche complexe,\nconventions fortes ?) then (oui)
  :Router vers exécutif\n(V4-Flash-FT);
else (non)
  :Résoudre avec V4-Pro\n(architecture, décision);
endif

|Modèle ciblé|
:Génère le code/output\n**dans mon style**,\n90%+ first-shot correct;
:Retourne la réponse;

stop
@enduml
----

=== 17€/月から始め、必要に応じてスケールします。

Ollama Proプラン（年間17€/月）は3つの競合クラウドモデルを許可します。このアーキテクチャでは、同時に2～3人の専門家以上が必要になることは決してありません：

* 分類フェーズ (V4-Pro) は 1 スロットを占有し、数秒かかります
* 対象のエキスパートは1スロットを占有し、応答を生成するのに時間がかかる
* 3番目のスロットは並列タスク用に予備として残されます

使用量が増えると、Docker方法で説明されているように、xref:0120_cumuler_deux_abonnements_ollama_pro_docker_post.adoc[私の記事（サブスクリプションの併用について）] で追加のProアカウントを追加します。月額100ユーロのMaxプランはありません — 本当に必要なものだけを追加します。

唯一の制限要因は**GPU時間のクォータ**Ollamaの月額（プロ向け無料プランの50倍）。私の1日数百回の利用では十分です。

[IMPORTANT]
====
V4-Pro (49B が有効) と Gemma 4 26B-A4B (3.8B が有効) の呼び出しのマージナルコストは**私にとってもゼロ**. これは Ollama のプランがコンピュートの差を吸収しています。私の唯一の指標はレイテンシです。
====

=== 実践におけるルーティング&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;Volume de requêtes estimé : ~500/jour&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;├─ 50% → Gemma 4 26B-A4B-FT    (micro, 3.8B actifs)
│        Formatage AsciiDoc, scripts simples, conventions nommage
│
├─ 25% → V4-Flash-FT            (exécutif, 13B actifs)
│        Plugins Gradle, refactoring Kotlin, génération DAG
│
├─ 15% → Qwen 35B MoE-FT       (micro, 3B actifs)
│        Tâches intermédiaires, review de code, documentation
│
└─ 10% → V4-Pro                 (orkestrateur, 49B actifs)
         Décisions architecturales, refactoring transverse,
         problèmes vraiment nouveaux&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;トラフィックの大部分は小規模なものによって処理されます。大規模モデルは最後の手段としてのみ介入します。

== 痛い比較：Claude, GPT, Gemini, Grok vs 私の艦隊

ここで差がとんでもなく広がります。同じ作業量（1日あたり500リクエスト、平均で入力約300トークン＋出力2,000トークン）のコストが、2026年5月の市場のプロプライエタリーソリューションではどれくらいか見てみましょう。

=== Anthropic — Claude (2026年5月料金)

Anthropic は最近、価格を*引き下げ*ました。DeepSeek や Qwen のようなオープンウェイト ソリューションによるプレッシャーが感じられます。

[cols=&amp;quot;3,2,2,2,2&amp;quot;]
|===
|モデル |$/MTok |$/MTok |1日あたりのコスト |**月額**

|Opus 4.7 (最も賢い) |$5 |$25 |$25.75 |**$772** |ソネット 4.6 (バランス) |$3 |$15 |$15.45 |**$463** |Haiku 4.5 (より高速) |$1 |$5 |$5.15 |**154ドル**
|===

[CAUTION]
====
これらの料金は *après* アンソロピックの最後の値下げ (2026年5月) の後です。それ以前、OpusはMTokあたり$15/$75でした。オープンウェイトへの恐れは現実です。
====

Claudeでも最も安いモデル — Haiku 4.5 へ**154ユーロ/月**— Ollama Pro のサブスクリプション（17ユーロ）の9倍以上かかる。 Haikuは私のコードベースを知らず、私のスタイルで生成せず、体系的なプロンプトエンジニアリングを必要とする。

最も賢い — Opus 4.7 — 予算を爆発させる**772ユーロ/月**1日あたり500件という少量のクエリに対して。あるいは**45倍高い**私の解決策より

=== OpenAI — GPT (料金 2026年5月)

[cols=&amp;quot;3,2,2,2,2&amp;quot;]
|===
|モデル |$/MTok |$/Tok |1日あたりのコスト |**月�額費用**

|GPT 5.5 (最も賢い) |$5 |$30 |$30.90 |**$927** |GPT 5.4 (標準) |$2.50 |$15 |$15.45 |**$463** |GPT 5.4 ミニ |$0.75 |$4.50 |$4.64 |**139ドル**
|===

OpenAIの『経済的』モデル — GPT 5.4 Mini 月額139ユーロ — でも、私のサブスクリプションの8倍のコストがかかります。それは私の慣習について*何も*知らないモデルであり、重いプロンプトエンジニアリングが必要です。

GPT 5.5、彼らのフラッグシップ：**927ユーロ/月**. *ゼロショット* を使うために。 スタイルが習熟していないため、タスクあたり2-3回の反復が必要で、実際の月間コストが簡単に倍増します。

=== Google — Gemini (2026年5月料金)

[cols=&amp;quot;3,2,2,2,2&amp;quot;]
|===
|モデル |$/MTok |$/MTok |コスト/日 |**月額コスト**

|Gemini 3.1 Pro (High) |$3.50 |$17.50 |$18.00 |**$540** |Gemini 3.1 Pro |$2 |$10 |$10.30 |**309ドル** |ジェミニ 3 フラッシュ |$0.30 |$1.50 |$1.54 |**$46**
|===

Gemini 3 Flash は月額46ユーロで価格面で競争力があります — しかしファインチューニングがなければ、汎用的なコードを生成します。*Cheroliv* コードではありません。

=== Grok — xAI (2026年5月の料金)

[cols=&amp;quot;3,2,2,2,2&amp;quot;]
|===
|モデル |$/MTok |$/MTok |コスト/日 |**費用/月**

|Grok 4 |$4 |$16 |$16.48 |**494ドル** |Grok 4 ミニ |$0.80 |$3.20 |$3.30 |**$99**
|===

=== Microsoft — Azure OpenAI (2026年5月の料金)

Azureは直接のOpenAI APIと同じ価格を適用しますが、インフラストラクチャとネットワークについても追加で請求します。マネージドサービスについては10-20％の追加コストを見込む必要があります。

[cols=&amp;quot;3,2,2,2,2&amp;quot;]
|===
|モデル |$/MTok |出力 $/MTok |コスト/日 |**月額コスト**

|GPT 5.4 (Azure, Global) |$2.50 |$15 |$15.45 |**$463** |GPT 5.4 + インフラストラクチャー |追加費用 15% |追加費用15% |$17.77 |**$533**
|===

[NOTE]
====
上記の料金はAPI向けのもので、チャット向けのサブスクリプション（Claude Proは月額20ドル、ChatGPT Plusは月額20ドル）ではありません。ここで比較するのは開発者向けの使用法です。つまり、APIを通じて1日に何百件ものリクエストを連続して行い、コードの生成、リファクタリング、ドキュメント作成を行う使い方です。一般向けのサブスクリプションでは、500件/日をはるかに超える前にクォータが達してしまいます。
====

=== 最終比較表

[cols=&amp;quot;3,2,2,2,2,2&amp;quot;]
|===
|解決策 |コードベースの知識 |統合スタイル |月額費 |イテレーション |**実効コスト**

|**私の艦隊 (Ollama Pro)** |�✅ ファインチューン済み |�✅ 重さの中では |**17ユーロ** |0-1 |**17ユーロ** |Claude Opus 4.7 |�❌ ゼロショット |❌ 必要なプロンプト |$772 |2-3 |$1 500-2 300 |クロード ハイク 4.5 |�❌ ゼロショット |❌ プロンプト 必要 |$154 |3-4 |$460-615 |GPT 5.5 |�❌ ゼロショット |�❌ 必要なプロンプト |$927 |2-3 |$1 854-2 781 |GPT 5.4 |�❌ ゼロショット |❌ プロンプトが必要 |$463 |2-3 |$925-1 390 |GPT 5.4 ミニ |�❌ ゼロショット |�❌ 必要なプロンプト |$139 |3-5 |$417-695 |Gemini 3.1 Pro ハイ |❌ ゼロショット |❌ プロンプトが必要です |$540 |2-3 |$1 080-1 620 |Grok 4 |�❌ ゼロショット |�❌ プロンプトが必要です |$494 |2-3 |$988-1 482 |**Azure GPT 5.4** |�❌ ゼロショット |�❌ 必要なプロンプト |$533 |2-3 |$1 066-1 600
|===

[plantuml, cost-comparison, svg]&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;@startuml
skinparam backgroundColor #FAFAFA&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;title コスト/効率レポート — 私の艦隊対市場（2026年5月）
rectangle &amp;quot;17€/月&amp;quot; as OURS #4ECDC4
rectangle &amp;quot;オーパス 4.7
772€&amp;quot; as OPUS #FF6B6B
rectangle &amp;quot;ソネット 4.6
463ユーロ&amp;quot; as SONNET #FF8B94
rectangle &amp;quot;GPT 5.5
927€&amp;quot; as GPT #FFD93D
rectangle &amp;quot;Gemini 3.1 Pro
540ユーロ&amp;quot; as GEMINI #6C5CE7
rectangle &amp;quot;Grok 4
494ユーロ&amp;quot; as GROK #A8E6CF
rectangle &amp;quot;python
import sys
sys.stdout.write(sys.stdin.read())&amp;quot; as HAIKU #DFE6E9
rectangle &amp;quot;GPT 5.4 Mini
139€&amp;quot; as MINI #B2BEC3&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;note bottom of OURS
  Avec fine-tune intégré.
  Zéro prompt engineering.
  90%+ first-shot correct.
end note&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;@enduml&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;17€/月、ファインチューニング済みの23名のAIエキスパートに。フラッグシップ Claude Opus 4.7の価格は**45倍高い***私の*コードベースにおいて品質が低いものに対して。 GPT 5.5はコストがかかる。**54倍高い**. 市場で最も安いモデル（Gemini Flash 46ユーロ）でも**2.7倍**私のワークスペースを知らないまま。

判断は覆せない：2026年のMoEアーキテクチャーへのファインチューニングは、ただ「安い」だけではない。これは効率性の要因だ**27× から 54×**プロプライエタリーソリューションとのコスト/品質比において。Anthropic, OpenAI, Google — すべてそれを知っており、だからこそ彼らはパニックで価格を引き下げている。

== 効率の係数 : 5-8× vs V4-Proを単独で使用する

両極を比較しましょう。

=== シナリオA:V4-Proのみで全て対応

[cols=&amp;quot;3,2&amp;quot;]
|===
|メトリック |値

|コードベースの知識 |0 (ゼロショット) |命名規則 |最初のショットで40-60%正解 |プロンプトエンジニアリングが必要 |はい、体系的 |タスクごとのイテレーション |2-3 |推論コスト |$100/月 (Ollama Max) |平均レイテンシ |~20 tok/s + ネットワーク
|===

=== シナリオ B : オーケストレーションされた MoE フリート

[cols=&amp;quot;3,2&amp;quot;]
|===
|メートル |価値

|コードベースの知識 |統合された（ファインチューン） |命名規約 |90-95% の初回正解率 |プロンプトエンジニアリング |いいえ（スタイルは重みの中にある） |タスクごとのイテレーション |0-1 |推論コスト |$60/月 (3× Ollama Pro) |平均遅延 |~50 トークン/秒 (軽量モデル)
|===

[cols=&amp;quot;4,2,2,2&amp;quot;]
|===
|次元 |V4-Pro だけ |艦隊 MoE |要因

|クラウドの月間コスト |$100 |**60ドル** |1.7× |注入されるコンテキスト |高い (プロンプト) |**ゼロ** |�∞ |平均反復 |2-3 |**0-1** |2-3× |感じられるレイテンシ |20 tok/s |50 tok/s |**2.5×** |最初の一発が正解 |50% |90%+ |**1.8倍**
|===

**総合的効率係数 : 5-8×**— 感じられる開発者の生産性.

[NOTE]
====
因子はトークンでもドルでも測定されません。それは「モデルに説明するのにどれだけの時間を費やすか」で測られます。ファインチューンされたモデルでは、この時間はゼロに近づきます。
====

== 完全予算：ワンショット投資、ばかげた定額プラン

[cols=&amp;quot;3,2&amp;quot;]
|===
|ポスト |金額

|GPUのトレーニング (811 H100-h, Crusoe $2/h) |**$1,622** |合成データセットの生成 (LLM API) |**400ドル** |推論 (Ollama Pro 年額, $17/月) |**$204** |**合計 初年度** |**$2 226** |**月額相当** |**$186** |**クエリあたりの推定コスト** |&amp;amp;lt; $0.01
|===

[plantuml, budget-breakdown, svg]&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;@startuml
skinparam backgroundColor #FAFAFA&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;rectangle &amp;quot;予算 年1 : $2 226&amp;quot; as Total #E8E8E8 {
  rectangle &amp;quot;GPUのトレーニング
$1 622 (73%)&amp;quot; as Train #FF6B6B
  rectangle &amp;quot;データセット
蒸留
$400 (18%)&amp;quot; as Data #FFE66D
  rectangle &amp;quot;Ollama Pro
$204 (9%)&amp;quot; as Cloud #4ECDC4
}&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;note bottom of Total
   $186/mois équivalent année 1.
   Dès l&amp;amp;#8217;an 2 : $17/mois.
   Amorti par ~$235 de CA
   mensuel avec marge 95%.
end note&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;@enduml&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;$186/月　最初の年**$17/月**2年目から。Netflixプレミアムプランの価格は、24時間365日対応可能な23人のAI専門家チームのためのもので、彼らは私のスタイルでコードを書き、*私のスタイル* で、私が彼らにコーディング規約を説明する必要がない。

=== 収益性の計算

edster.cloud と その マージン が 約 95% の 場合 、 損益分岐点は**約2,340ドルの追加の売上高**今年。実際：

* 1 件のソフトウェアパイロットミッション → $3 000-5 000 → 投資がカバー + 利益
* 1 企業研修 → $5 000-10 000 → 快適
* 暗黙的なアップセル : 「私のAIチームは私のソフトウェアフォージをマスターしている」 → 商業的差別化

2年目以降、トレーニングの支払いは不要になります（データセットの更新がある場合を除く）。年間コストは**$204**(17ドル/月). コスト/価値の比率はユニコーンのようにほぼゼロです。

== 演習の限界

これはまだ*ざっくりとした見積もり*。いくつかの変数が予算に影響を与える可能性があります：

[cols=&amp;quot;2,3&amp;quot;]
|===
|変数 |影響

|合成データセットの生成 |もし蒸留APIが失敗する（幻覚、不適切に形成されたペア）場合、人間の時間を使ってキュレートする必要があります。隠れたコスト。 |OllamaのGPU時間のクォータ |使用量がProプランの割り当てを超える場合は、プランをアップグレードするか、専用のGPUに切り替える必要があります。 |ファインチューンの実効的な品質 |ファインチューンが失敗 → やり直し。本当のリスクはハイパーパラメータで、GPUの場所ではない。 |モデルの急速な進化 |Qwen3.6/Gemma 4 は1か月未満前にリリースされました。6か月後、次の世代はさらに優れ、ファインチューニングももっと安くなります。
|===

[WARNING]
====
まず1つだけのマイクロモデルでパイプラインをテストせずに、811時間のトレーニングを実行しないでください。Qwen 35B-A3Bで3-4hのランを実行すると、コストは$8になります。データセットがダメなら、$8でわかります。$1 622ではありません。
====

== 結論：ファインチューンはアクセシブルなラグジュアリーになった

1年前、292B パラメータのモデルをファインチューニングすること（QLoRA でも）は研究の領域だった。今日、2026年5月において、これは独立した開発者にとって実現可能なプロジェクトです：

* **811 H100-時間**トレーニング — $1 622 Crusoe で
* **23の専門モデル**Ollama Cloud上にロードされました —**$17/月**
* **0サーバー, 0ローカルGPU, 0メンテナンスインフラ**

民主化は三つの収斂する要因からもたらされた：

1. **MoEアーキテクチャ**— これにより、一部の重みのみが活性化されるモデルを効率的にファインチューニングすることができます
2. **Ollama Cloudの固定プラン**— 変動コスト（per‑token）を固定コスト（サブスクリプション）に変換する
3. **高品質なオープンウェイトモデル**— DeepSeek V4, Qwen3.6, Gemma 4はMIT/Apache 2.0ライセンスのもとにあります。

文明は、考えずに行える重要な操作の数を増やすことによって進歩する。

ファインチューンとはまさにこれです：機械に任せる作業で、それについて考える必要がなくなるものです。そして2026年には、ジュニア開発者の月給よりも安いコストで済みます。

---

_記事は{jbake-date}に公開されました_

== フリートのファインチューンされたモデル

[cols=&amp;quot;2,2,2,2,3&amp;quot;]
|===
|サイズが有効になりました |数 |ベースモデル |分野 |データセット

|13B |1 |ディープシーク-V4-フラッシュ-ベース |一般的なワークスペース |50M トークン |13B |5 |DeepSeek-V4-Flash |グラドル, コトリン, ディーエージー, ドキュメント, インフラ |15Mトークン |3.8B |6 |Gemma 4 26B-A4B |マイクロタスク、フォーマット、スクリプト |5Mトークン |3B |5 |Qwen3.6-35B-A3B |リファクタリング, レビュー, 中間ドキュメント |5Mトークン |3B |5 |Qwen3.5-35B-A3B |レガシータスク、 互換性 |5Mトークン
|===

== リソース

=== HuggingFaceのオープンウェイトモデル

* https://huggingface.co/deepseek-ai/DeepSeek-V4-Flash-Base[DeepSeek V4-Flash-Base — 292B パラメータ, ライセンス MIT]
* https://huggingface.co/Qwen/Qwen3.6-35B-A3B[Qwen3.6-35B-A3B — 35B/3B が有効、ライセンスは Apache 2.0]
* https://huggingface.co/Qwen/Qwen3.5-35B-A3B[Qwen3.5-35B-A3B — 35B/3B 有効, Apache 2.0 ライセンス]
* https://huggingface.co/google/gemma-4-26B-A4B-it[Gemma 4 26B-A4B — 26B/3.8B が有効、Apache 2.0 ライセンス]

=== 料金の出典（2026年5月）

* https://ollama.com/pricing[Ollama Cloud 料金 — Proプラン $17/月 年払い]
* https://www.anthropic.com/pricing[Anthropic 料金 — Claude API (Opus 4.7 $5/$25, Sonnet 4.6 $3/$15, Haiku 4.5 $1/$5)]
* https://openai.com/api/pricing/[OpenAI の料金 — GPT API (GPT 5.5 $5/$30、GPT 5.4 $2.50/$15)]
* https://deepinfra.com/pricing[DeepInfraの料金 — GPUインスタンス H100 $1.79/時、B200 $2.79/時]
* Vast.ai, Crusoe Cloud, FluidStack, TensorDock, RunPod, CoreWeave, Lambda Labs — manual price listings, dated May 2026

=== 公式発表

* https://qwen.ai/blog?id=qwen3.6-35b-a3b[公式発表 Qwen3.6-35B-A3B — Qwenブログ]— エージェンティックコーディング, Apache 2.0, 262Kコンテキスト&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;</description>
        </item><item>
            <title>ホーム Gradle プラグイン：2つの Ollama Pro インスタンスを並列で制御する</title>
            <link >https://cheroliv.com/blog/2026/0121_plugin_gradle_piloter_deux_instances_ollama_pro_post.html</link>
            <pubDate>Fri, 8 May 2026 00:00:00 +0000</pubDate>
            <guid isPermaLink="false">blog/2026/0121_plugin_gradle_piloter_deux_instances_ollama_pro_post.html</guid>
            <description>&amp;lt;div id=&amp;quot;toc&amp;quot; class=&amp;quot;toc&amp;quot;&amp;gt;
&amp;lt;div id=&amp;quot;toctitle&amp;quot;&amp;gt;Table des matières&amp;lt;/div&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel1&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_紹介&amp;quot;&amp;gt;紹介&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_なぜgradleをインフラに使うのか&amp;quot;&amp;gt;なぜGradleをインフラに使うのか？&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_build_gradle_kts_完全版&amp;quot;&amp;gt;build.gradle.kts 完全版&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_キータスクの解剖&amp;quot;&amp;gt;キータスクの解剖&amp;lt;/a&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel2&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_startollamab_ランチャー&amp;quot;&amp;gt;startOllamaB` — ランチャー&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_signinb_インタラクティブ&amp;quot;&amp;gt;signInB` — インタラクティブ&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_pullmodelb_設定可能な&amp;quot;&amp;gt;pullModelB` — 設定可能な&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_statusollamaall_診断&amp;quot;&amp;gt;statusOllamaAll` — 診断&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_cleanollamab_アイデンティティを保つクリーニング&amp;quot;&amp;gt;cleanOllamaB` — アイデンティティを保つクリーニング&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_完全なワークフロー_ゼロから二つのセッションまで&amp;quot;&amp;gt;完全なワークフロー — ゼロから二つのセッションまで&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_なぜgradleプラグインとして作らないのか&amp;quot;&amp;gt;なぜGradleプラグインとして作らないのか？&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_学んだ教訓&amp;quot;&amp;gt;学んだ教訓&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_結論&amp;quot;&amp;gt;結論&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_リソース&amp;quot;&amp;gt;リソース&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div id=&amp;quot;preamble&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;読了時間 : 18 minutes&amp;lt;/div&amp;gt;
&amp;lt;p&amp;gt;なぜ手動でdockerコマンドを打つのですか？Gradleのタスクにすべてをカプセル化できるのに。これが、外部のシェルスクリプトをゼロにしてデュアルOllama Proの設定をどのように産業化したかです。起動、停止、アイデンティティ、サインイン、プル — すべてこれが経由します`./gradlew`。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_紹介&amp;quot;&amp;gt;紹介&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;前の記事では、Ollama Pro の二つのアカウントを同じマシンで共存させる方法を示しました。その際、二番目のインスタンスを Docker コンテナ内に隔離しました。設定は機能しますが、日常の管理はすぐに面倒になります：コンテナの名前を覚えておく必要があり、適切なコマンドを再実行しなければなりません。&amp;lt;code&amp;gt;docker exec&amp;lt;/code&amp;gt;, チェッカー どのポートがアクティブか&amp;amp;#8230;&amp;amp;#8203;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;あなたは、14のターミナルを開いているその瞬間を知っているでしょう、あなたはタイプしている`docker exec ollama-instance-b ollama list`4回目で、そしてあなたは「もっときれいな方法があるはずだ」と思いますか？&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;この方法はGradleです。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;コードをビルドするためだけではない。Gradleはローカルインフラストラクチャの指揮者のように、プロビジョニング、検証、テスト、クリーンアップを行うタスク。すべてがバージョン管理された`build.gradle.kts`� 隣に住んでいる`docker-compose.yml`。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
!theme plain

skinparam handwritten false
skinparam shadowing false
skinparam BoxPadding 8
skinparam DefaultFontSize 11
skinparam ArrowThickness 1.5

left to right direction

actor &amp;quot;開発者&amp;quot; as Dev

package &amp;quot;build.gradle.kts&amp;quot; as GradleFile {

  usecase &amp;quot;OllamaBを開始&amp;quot; as Start
  usecase &amp;quot;stopOllamaB&amp;quot; as Stop
  usecase &amp;quot;checkIdentity&amp;quot; as Check
  usecase &amp;quot;signInB&amp;quot; as SignIn
  usecase &amp;quot;pullModelB&amp;quot; as Pull
  usecase &amp;quot;testOllamaB&amp;quot; as Test
  usecase &amp;quot;statusOllamaAll&amp;quot; as Status
  usecase &amp;quot;cleanOllamaB&amp;quot; as Clean
}

package &amp;quot;Docker デーモン&amp;quot; as DockerDaemon {

  node &amp;quot;ollama-instance-b&amp;quot; as ContainerB {
    component &amp;quot;:11435&amp;quot; as Port
    database &amp;quot;~/ollama-b-data&amp;quot; as Volume
  }
}

package &amp;quot;Ollama ネイティブ&amp;quot; as Native {
  component &amp;quot;:11434&amp;quot; as NatPort
}

Dev --&amp;amp;gt; Start
Dev --&amp;amp;gt; SignIn
Dev --&amp;amp;gt; Pull
Dev --&amp;amp;gt; Test
Dev --&amp;amp;gt; Status
Dev --&amp;amp;gt; Check
Dev --&amp;amp;gt; Stop
Dev --&amp;amp;gt; Clean

Start ..&amp;amp;gt; ContainerB : docker run -d
Stop ..&amp;amp;gt; ContainerB : docker stop
Check ..&amp;amp;gt; Volume : cat id_ed25519.pub
SignIn ..&amp;amp;gt; ContainerB : ollama signin
Pull ..&amp;amp;gt; ContainerB : ollama pull
Test ..&amp;amp;gt; ContainerB : curl /v1/chat/completions
Status ..&amp;amp;gt; ContainerB : docker ps
Status ..&amp;amp;gt; Native : curl :11434
Clean ..&amp;amp;gt; ContainerB : docker rm -f

note bottom of GradleFile
  Zéro script bash externe.
  Tout est dans le build.gradle.kts,
  versionné avec le projet.
end note

@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_なぜgradleをインフラに使うのか&amp;quot;&amp;gt;なぜGradleをインフラに使うのか？&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;その質問は正当です。Gradleはビルドツールです。通常、コンパイルし、テストし、パッケージングします。Dockerコンテナを起動するわけではありません。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;ただし、Gradleは依存グラフエンジンでもあり、それが私たちのケースにとって興味深い点です。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;欲しいです：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;olist arabic&amp;quot;&amp;gt;
&amp;lt;ol class=&amp;quot;arabic&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;コンテナがサインイン前に起動されるように&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;モデルをプルする前に身元を確認して&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;コンテナがダウンしている場合、APIテストは静かに失敗します&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ol&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;�純粋な依存グラフ。Gradleはそれにぴったりです。Kotlin DSLはタスクの記述をスムーズにし、`doLast`システムコマンドをアプリケーションコードのように実行できます。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;特に：bashrc を維持する必要はなく、放置されたスクリプトも中にない`~/bin`, Makefileがdocker-composeの隣にありません。すべてが一つのファイルに収まっており、プロジェクトのコードと同じ場所にあります。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_build_gradle_kts_完全版&amp;quot;&amp;gt;build.gradle.kts 完全版&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;これが私がやっと書き終わったファイルです。これは、ボリュームのプロビジョニングから検証の curl、さらにインタラクティブなサインインまで、すべてをこなします。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-kotlin hljs&amp;quot; data-lang=&amp;quot;kotlin&amp;quot;&amp;gt;import java.io.ByteArrayOutputStream

plugins {
    base
}

// -------------------------------------------------------------------------
// Configuration
// -------------------------------------------------------------------------
val instanceName   = &amp;quot;ollama-instance-b&amp;quot;
val instancePort   = 11435
val instanceImage  = &amp;quot;ollama/ollama:0.20.2&amp;quot;
val dataDir        = file(&amp;quot;${System.getProperty(&amp;quot;user.home&amp;quot;)}/ollama-b-data&amp;quot;)
val nativePort     = 11434

// Modèles à gérer — cloud Pro + un modèle local gratuit pour les tests
val proModels      = listOf(&amp;quot;deepseek-v4-pro:cloud&amp;quot;, &amp;quot;gemma4:31b-cloud&amp;quot;)
val freeModels     = listOf(&amp;quot;qwen3:0.6b&amp;quot;)

// -------------------------------------------------------------------------
// Tâche préparatoire — création du volume si absent
// -------------------------------------------------------------------------
val prepareVolume by tasks.registering {
    group       = &amp;quot;ollama&amp;quot;
    description = &amp;quot;Crée le répertoire de volume pour l&amp;#39;instance B si absent&amp;quot;
    doLast {
        if (!dataDir.exists()) {
            dataDir.mkdirs()
            println(&amp;quot;Volume créé : ${dataDir.absolutePath}&amp;quot;)
        } else {
            println(&amp;quot;Volume existant : ${dataDir.absolutePath}&amp;quot;)
        }
    }
}

// -------------------------------------------------------------------------
// Démarrage du conteneur Docker
// -------------------------------------------------------------------------
val startOllamaB by tasks.registering(Exec::class) {
    group       = &amp;quot;ollama&amp;quot;
    description = &amp;quot;Lance le conteneur Docker pour l&amp;#39;instance Ollama B&amp;quot;
    dependsOn(prepareVolume)

    commandLine(
        &amp;quot;docker&amp;quot;, &amp;quot;run&amp;quot;, &amp;quot;-d&amp;quot;,
        &amp;quot;--name&amp;quot;, instanceName,
        &amp;quot;-p&amp;quot;, &amp;quot;$instancePort:11434&amp;quot;,
        &amp;quot;-v&amp;quot;, &amp;quot;${dataDir.absolutePath}:/root/.ollama&amp;quot;,
        &amp;quot;-e&amp;quot;, &amp;quot;OLLAMA_HOST=0.0.0.0&amp;quot;,
        &amp;quot;--restart&amp;quot;, &amp;quot;always&amp;quot;,
        instanceImage
    )
    isIgnoreExitValue = true

    doLast {
        val alreadyRunning = executionResult.get().exitValue != 0
        if (alreadyRunning) {
            logger.lifecycle(&amp;quot;Le conteneur &amp;#39;$instanceName&amp;#39; existe déjà — tentative de démarrage&amp;quot;)
        } else {
            logger.lifecycle(&amp;quot;Conteneur &amp;#39;$instanceName&amp;#39; lancé&amp;quot;)
        }
    }
}

// -------------------------------------------------------------------------
// Arrêt du conteneur
// -------------------------------------------------------------------------
val stopOllamaB by tasks.registering(Exec::class) {
    group       = &amp;quot;ollama&amp;quot;
    description = &amp;quot;Arrête le conteneur Docker de l&amp;#39;instance B&amp;quot;

    commandLine(&amp;quot;docker&amp;quot;, &amp;quot;stop&amp;quot;, instanceName)
    isIgnoreExitValue = true

    doLast {
        logger.lifecycle(&amp;quot;Conteneur &amp;#39;$instanceName&amp;#39; arrêté&amp;quot;)
    }
}

// -------------------------------------------------------------------------
// Affichage de la clé publique (Device Key)
// -------------------------------------------------------------------------
val checkIdentity by tasks.registering(Exec::class) {
    group       = &amp;quot;ollama&amp;quot;
    description = &amp;quot;Affiche la clé publique SSH de l&amp;#39;instance B&amp;quot;
    dependsOn(startOllamaB)

    commandLine(&amp;quot;docker&amp;quot;, &amp;quot;exec&amp;quot;, instanceName, &amp;quot;cat&amp;quot;, &amp;quot;/root/.ollama/id_ed25519.pub&amp;quot;)
    standardOutput = ByteArrayOutputStream()

    doLast {
        val pubKey = standardOutput.toString().trim()
        println(&amp;quot;=&amp;quot;.repeat(60))
        println(&amp;quot;Device Key (Instance B)&amp;quot;)
        println(&amp;quot;=&amp;quot;.repeat(60))
        println(pubKey)
        println(&amp;quot;=&amp;quot;.repeat(60))
        println(&amp;quot;→ Enregistre cette clé sur https://ollama.com/settings/keys&amp;quot;)
        println(&amp;quot;→ Puis exécute : ./gradlew signInB&amp;quot;)
        println(&amp;quot;=&amp;quot;.repeat(60))
    }
}

// -------------------------------------------------------------------------
// Sign-in interactif (Ouvrira le navigateur)
// -------------------------------------------------------------------------
val signInB by tasks.registering(Exec::class) {
    group       = &amp;quot;ollama&amp;quot;
    description = &amp;quot;Lance l&amp;#39;authentification interactive Ollama pour le compte B&amp;quot;
    dependsOn(startOllamaB)

    standardInput  = System.`in`
    standardOutput = System.out
    errorOutput    = System.err

    commandLine(&amp;quot;docker&amp;quot;, &amp;quot;exec&amp;quot;, &amp;quot;-it&amp;quot;, instanceName, &amp;quot;ollama&amp;quot;, &amp;quot;signin&amp;quot;)

    doFirst {
        logger.lifecycle(&amp;quot;Authentification pour le Compte Pro B...&amp;quot;)
        logger.lifecycle(&amp;quot;Ouvre ton navigateur et connecte-toi avec l&amp;#39;email du compte B&amp;quot;)
    }
}

// -------------------------------------------------------------------------
// Pull d&amp;#39;un modèle (paramétrable via propriété Gradle)
// -------------------------------------------------------------------------
val pullModelB by tasks.registering(Exec::class) {
    group       = &amp;quot;ollama&amp;quot;
    description = &amp;quot;Pull un modèle sur l&amp;#39;instance B. Usage : ./gradlew pullModelB -Pmodel=nom:tag&amp;quot;
    dependsOn(startOllamaB)

    val modelName = project.findProperty(&amp;quot;model&amp;quot;) as? String ?: &amp;quot;qwen3:0.6b&amp;quot;

    commandLine(&amp;quot;docker&amp;quot;, &amp;quot;exec&amp;quot;, instanceName, &amp;quot;ollama&amp;quot;, &amp;quot;pull&amp;quot;, modelName)

    doFirst {
        logger.lifecycle(&amp;quot;Pull du modèle &amp;#39;$modelName&amp;#39; sur l&amp;#39;instance B...&amp;quot;)
    }

    doLast {
        logger.lifecycle(&amp;quot;Modèle &amp;#39;$modelName&amp;#39; pullé avec succès&amp;quot;)
    }
}

// -------------------------------------------------------------------------
// Pull de tous les modèles Pro (batch)
// -------------------------------------------------------------------------
val pullAllProModels by tasks.registering {
    group       = &amp;quot;ollama&amp;quot;
    description = &amp;quot;Pull tous les modèles cloud Pro sur l&amp;#39;instance B&amp;quot;
    dependsOn(startOllamaB)

    doLast {
        proModels.forEach { model -&amp;amp;gt;
            logger.lifecycle(&amp;quot;→ Pull $model...&amp;quot;)
            val process = ProcessBuilder(&amp;quot;docker&amp;quot;, &amp;quot;exec&amp;quot;, instanceName, &amp;quot;ollama&amp;quot;, &amp;quot;pull&amp;quot;, model)
                .inheritIO()
                .start()
            process.waitFor()
        }
        logger.lifecycle(&amp;quot;Tous les modèles Pro pullés&amp;quot;)
    }
}

// -------------------------------------------------------------------------
// Pull de tous les modèles gratuits (batch / première install)
// -------------------------------------------------------------------------
val pullAllFreeModels by tasks.registering {
    group       = &amp;quot;ollama&amp;quot;
    description = &amp;quot;Pull tous les modèles locaux gratuits sur l&amp;#39;instance B&amp;quot;
    dependsOn(startOllamaB)

    doLast {
        freeModels.forEach { model -&amp;amp;gt;
            logger.lifecycle(&amp;quot;→ Pull $model...&amp;quot;)
            val process = ProcessBuilder(&amp;quot;docker&amp;quot;, &amp;quot;exec&amp;quot;, instanceName, &amp;quot;ollama&amp;quot;, &amp;quot;pull&amp;quot;, model)
                .inheritIO()
                .start()
            process.waitFor()
        }
        logger.lifecycle(&amp;quot;Tous les modèles gratuits pullés&amp;quot;)
    }
}

// -------------------------------------------------------------------------
// Liste des modèles disponibles sur l&amp;#39;instance B
// -------------------------------------------------------------------------
val listModelsB by tasks.registering(Exec::class) {
    group       = &amp;quot;ollama&amp;quot;
    description = &amp;quot;Liste les modèles disponibles sur l&amp;#39;instance B&amp;quot;
    dependsOn(startOllamaB)

    commandLine(&amp;quot;docker&amp;quot;, &amp;quot;exec&amp;quot;, instanceName, &amp;quot;ollama&amp;quot;, &amp;quot;list&amp;quot;)
}

// -------------------------------------------------------------------------
// Health check — test API sur les deux instances
// -------------------------------------------------------------------------
val testOllamaB by tasks.registering {
    group       = &amp;quot;ollama&amp;quot;
    description = &amp;quot;Teste la connectivité API de l&amp;#39;instance B avec un simple chat&amp;quot;
    dependsOn(startOllamaB)

    doLast {
        val model = project.findProperty(&amp;quot;model&amp;quot;) as? String ?: &amp;quot;qwen3:0.6b&amp;quot;
        logger.lifecycle(&amp;quot;Test de l&amp;#39;instance B avec le modèle &amp;#39;$model&amp;#39;...&amp;quot;)

        val payload = &amp;quot;&amp;quot;&amp;quot;
            {
              &amp;quot;model&amp;quot;: &amp;quot;$model&amp;quot;,
              &amp;quot;messages&amp;quot;: [{&amp;quot;role&amp;quot;: &amp;quot;user&amp;quot;, &amp;quot;content&amp;quot;: &amp;quot;Réponds uniquement par OK&amp;quot;}],
              &amp;quot;max_tokens&amp;quot;: 5
            }
        &amp;quot;&amp;quot;&amp;quot;.trimIndent()

        val process = ProcessBuilder(
            &amp;quot;curl&amp;quot;, &amp;quot;-s&amp;quot;, &amp;quot;http://localhost:$instancePort/v1/chat/completions&amp;quot;,
            &amp;quot;-H&amp;quot;, &amp;quot;Content-Type: application/json&amp;quot;,
            &amp;quot;-d&amp;quot;, payload
        ).start()

        val response = process.inputStream.bufferedReader().readText()
        process.waitFor()

        if (response.contains(&amp;quot;\&amp;quot;id\&amp;quot;:\&amp;quot;chatcmpl&amp;quot;) || response.contains(&amp;quot;\&amp;quot;choices\&amp;quot;&amp;quot;)) {
            println(&amp;quot;✓ Instance B OK — port $instancePort répond&amp;quot;)
            println(&amp;quot;  Response: ${response.take(120)}...&amp;quot;)
        } else {
            println(&amp;quot;✗ Instance B INACTIVE — vérifie le conteneur avec &amp;#39;./gradlew statusOllamaAll&amp;#39;&amp;quot;)
            println(&amp;quot;  Raw: $response&amp;quot;)
        }
    }
}

// -------------------------------------------------------------------------
// Health check sur les deux instances simultanément
// -------------------------------------------------------------------------
val statusOllamaAll by tasks.registering {
    group       = &amp;quot;ollama&amp;quot;
    description = &amp;quot;Vérifie le statut des deux instances Ollama (native + Docker)&amp;quot;

    doLast {
        // Instance native
        runCatching {
            val process = ProcessBuilder(
                &amp;quot;curl&amp;quot;, &amp;quot;-s&amp;quot;, &amp;quot;-o&amp;quot;, &amp;quot;/dev/null&amp;quot;, &amp;quot;-w&amp;quot;, &amp;quot;%{http_code}&amp;quot;,
                &amp;quot;http://localhost:$nativePort/api/tags&amp;quot;
            ).start()
            val code = process.inputStream.bufferedReader().readText().trim()
            process.waitFor()
            println(if (code == &amp;quot;200&amp;quot;) &amp;quot;✓ Instance Native   — port $nativePort OK (HTTP $code)&amp;quot;
                    else &amp;quot;✗ Instance Native — port $nativePort (HTTP $code)&amp;quot;)
        }.getOrElse {
            println(&amp;quot;✗ Instance Native — injoignable sur le port $nativePort&amp;quot;)
        }

        // Instance Docker
        runCatching {
            val process = ProcessBuilder(
                &amp;quot;curl&amp;quot;, &amp;quot;-s&amp;quot;, &amp;quot;-o&amp;quot;, &amp;quot;/dev/null&amp;quot;, &amp;quot;-w&amp;quot;, &amp;quot;%{http_code}&amp;quot;,
                &amp;quot;http://localhost:$instancePort/api/tags&amp;quot;
            ).start()
            val code = process.inputStream.bufferedReader().readText().trim()
            process.waitFor()
            println(if (code == &amp;quot;200&amp;quot;) &amp;quot;✓ Instance Docker B — port $instancePort OK (HTTP $code)&amp;quot;
                    else &amp;quot;✗ Instance Docker B — port $instancePort (HTTP $code)&amp;quot;)
        }.getOrElse {
            println(&amp;quot;✗ Instance Docker B — injoignable sur le port $instancePort&amp;quot;)
        }

        // Info conteneur
        runCatching {
            val process = ProcessBuilder(&amp;quot;docker&amp;quot;, &amp;quot;ps&amp;quot;, &amp;quot;--filter&amp;quot;, &amp;quot;name=$instanceName&amp;quot;,
                &amp;quot;--format&amp;quot;, &amp;quot;table {{.Names}}\\t{{.Status}}\\t{{.Ports}}&amp;quot;).start()
            val status = process.inputStream.bufferedReader().readText()
            process.waitFor()
            println()
            println(&amp;quot;Conteneur Docker :&amp;quot;)
            println(status)
        }
    }
}

// -------------------------------------------------------------------------
// Nettoyage complet
// -------------------------------------------------------------------------
val cleanOllamaB by tasks.registering(Exec::class) {
    group       = &amp;quot;ollama&amp;quot;
    description = &amp;quot;Arrête et supprime le conteneur Docker de l&amp;#39;instance B&amp;quot;
    dependsOn(stopOllamaB)

    commandLine(&amp;quot;docker&amp;quot;, &amp;quot;rm&amp;quot;, instanceName)
    isIgnoreExitValue = true

    doLast {
        logger.lifecycle(&amp;quot;Conteneur &amp;#39;$instanceName&amp;#39; supprimé&amp;quot;)
        logger.lifecycle(&amp;quot;Le volume ${dataDir.absolutePath} est conservé (identité persistante)&amp;quot;)
    }
}

// -------------------------------------------------------------------------
// Affichage des instructions
// -------------------------------------------------------------------------
val helpOllama by tasks.registering {
    group       = &amp;quot;ollama&amp;quot;
    description = &amp;quot;Affiche l&amp;#39;aide des tâches Ollama disponibles&amp;quot;

    doLast {
        println(&amp;quot;&amp;quot;&amp;quot;
        ╔══════════════════════════════════════════════════════════════╗
        ║         Tâches Gradle — Pilotage Dual Ollama Pro            ║
        ╠══════════════════════════════════════════════════════════════╣
        ║  ./gradlew startOllamaB      Démarrer l&amp;#39;instance Docker B   ║
        ║  ./gradlew stopOllamaB       Arrêter l&amp;#39;instance Docker B    ║
        ║  ./gradlew checkIdentity     Afficher la clé SSH publique   ║
        ║  ./gradlew signInB           Sign-in interactif compte B    ║
        ║  ./gradlew pullModelB        Pull un modèle (-Pmodel=...)   ║
        ║  ./gradlew pullAllProModels  Pull tous les modèles Pro      ║
        ║  ./gradlew pullAllFreeModels Pull tous les modèles gratuits ║
        ║  ./gradlew listModelsB       Lister les modèles instance B  ║
        ║  ./gradlew testOllamaB       Test API avec un chat simple   ║
        ║  ./gradlew statusOllamaAll   Santé des 2 instances          ║
        ║  ./gradlew cleanOllamaB      Supprimer le conteneur         ║
        ║  ./gradlew helpOllama        Cette aide                     ║
        ╚══════════════════════════════════════════════════════════════╝
        &amp;quot;&amp;quot;&amp;quot;.trimIndent())
    }
}&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;はい、12のタスク、単一のエントリーポイント、摩擦ゼロ。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_キータスクの解剖&amp;quot;&amp;gt;キータスクの解剖&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_startollamab_ランチャー&amp;quot;&amp;gt;startOllamaB` — ランチャー&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;何も難しくない：一`docker run -d`正しい設定で。コツはそこにある`isIgnoreExitValue = true`。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-kotlin hljs&amp;quot; data-lang=&amp;quot;kotlin&amp;quot;&amp;gt;isIgnoreExitValue = true&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;コンテナが既に存在している場合、コマンド`docker run`失敗します (exit code ≠ 0)。このプロパティがない場合、Gradle はすべてのビルドをエラーで停止します。ここでは、失敗はサイレントです — そして`doLast`それが既に存在していたものか、本当のエラーかを検出する。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;Le `doLast`重要：コマンドの実行後に回転し、検査を可能にします。`executionResult.get().exitValue`適切なメッセージをログに出力する。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_signinb_インタラクティブ&amp;quot;&amp;gt;signInB` — インタラクティブ&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;これは人間のインタラクションが必要な唯一のタスクです。 Gradle は伝送します`System.in`プロンプトが出るようにプロセスに`ollama signin`正常に表示されるように：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-kotlin hljs&amp;quot; data-lang=&amp;quot;kotlin&amp;quot;&amp;gt;standardInput  = System.`in`
standardOutput = System.out
errorOutput    = System.err&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;それをしなければ、sign-in は stdin が閉じられているためブロックされ、プロンプトが表示されません。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_pullmodelb_設定可能な&amp;quot;&amp;gt;pullModelB` — 設定可能な&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;パラメータを経由して受け取る汎用タスク`-P` :&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;./gradlew pullModelB -Pmodel=deepseek-v4-pro:cloud
./gradlew pullModelB                           # fallback : qwen3:0.6b&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;フォールバックは重要です：`project.findProperty(&amp;quot;model&amp;quot;) as? String ?: &amp;quot;qwen3:0.6b&amp;quot;`パラメータを忘れてもタスクが壊れないことを保証します。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_statusollamaall_診断&amp;quot;&amp;gt;statusOllamaAll` — 診断&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;二`curl`港での健康`11434` et &amp;lt;code&amp;gt;11435&amp;lt;/code&amp;gt;, フォールバックで`runCatching`インスタンスのうちのいずれかがダウンしている場合でもクラッシュしないように。出力は構造化されています：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-text hljs&amp;quot; data-lang=&amp;quot;text&amp;quot;&amp;gt;✓ Instance Native   — port 11434 OK (HTTP 200)
✓ Instance Docker B — port 11435 OK (HTTP 200)

Conteneur Docker :
NAMES               STATUS         PORTS
ollama-instance-b   Up 3 hours     0.0.0.0:11435-&amp;amp;gt;11434/tcp&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;一目見ただけで、何がうまくいっているか、何がまずいのかすぐに分かる。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_cleanollamab_アイデンティティを保つクリーニング&amp;quot;&amp;gt;cleanOllamaB` — アイデンティティを保つクリーニング&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-kotlin hljs&amp;quot; data-lang=&amp;quot;kotlin&amp;quot;&amp;gt;commandLine(&amp;quot;docker&amp;quot;, &amp;quot;rm&amp;quot;, instanceName)
isIgnoreExitValue = true&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;コンテナは削除されていますが、ボリュームは`~/ollama-b-data`だ&amp;lt;strong&amp;gt;保存された&amp;lt;/strong&amp;gt;. SSHのアイデンティティはクリーニング後も生き残ります。 次の`startOllamaB`, 同じキーが再利用されます — サインインし直す必要も、Device Keyを再登録する必要もありません。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;admonitionblock caution&amp;quot;&amp;gt;
&amp;lt;table&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;icon&amp;quot;&amp;gt;
&amp;lt;i class=&amp;quot;fa icon-caution&amp;quot; title=&amp;quot;🔒&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;
&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;code&amp;gt;cleanOllamaB`ボリュームに触れないでください。Bのアイデンティティを消して（ゼロからやり直して）いきたい場合は、削除する必要があります。&amp;lt;/code&amp;gt;~/ollama-b-data`手動で。これは自発的 — 一つ`clean`認証情報を破壊してはならない。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/table&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_完全なワークフロー_ゼロから二つのセッションまで&amp;quot;&amp;gt;完全なワークフロー — ゼロから二つのセッションまで&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;プロジェクトに参加し、ドキュメントを開かずにすべてをセットアップしたい人向けの理想的な手順はこちらです。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-text hljs&amp;quot; data-lang=&amp;quot;text&amp;quot;&amp;gt;# 1. Premier contact — que faire ?
$ ./gradlew helpOllama

# 2. On démarre l&amp;#39;instance B
$ ./gradlew startOllamaB

# 3. On récupère la Device Key et on l&amp;#39;enregistre sur ollama.com
$ ./gradlew checkIdentity
# → copier-coller de la clé sur https://ollama.com/settings/keys

# 4. Authentification interactive
$ ./gradlew signInB

# 5. Pull d&amp;#39;un petit modèle gratuit pour tester la plomberie
$ ./gradlew pullModelB

# 6. Test API
$ ./gradlew testOllamaB

# 7. Si tout est vert, pull des modèles Pro
$ ./gradlew pullAllProModels

# 8. Vérification finale des deux instances
$ ./gradlew statusOllamaAll&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;2分未満ですべてプロビジョニングされます。READMEを読む必要も、環境変数を設定する必要もありません。タスク`helpOllama`組み込まれたドキュメントとして機能します。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
!theme plain
skinparam DefaultFontSize 11

actor Développeur as Dev
participant &amp;quot;Gradle
(build.gradle.kts)&amp;quot; as Gradle
participant &amp;quot;Docker
デーモン&amp;quot; as Docker
participant &amp;quot;Ollama
インスタンス B&amp;quot; as OllamaB
participant &amp;quot;Ollama
クラウド&amp;quot; as Cloud

== Provisionnement ==
Dev -&amp;amp;gt; Gradle : helpOllama
Gradle --&amp;amp;gt; Dev : Aide et instructions

Dev -&amp;amp;gt; Gradle : startOllamaB
Gradle -&amp;amp;gt; Docker : docker run -d ollama/ollama:0.20.2
Docker -&amp;amp;gt; OllamaB : Génération clés SSH (id_ed25519)
Docker --&amp;amp;gt; Gradle : conteneur lancé
Gradle --&amp;amp;gt; Dev : OK

Dev -&amp;amp;gt; Gradle : checkIdentity
Gradle -&amp;amp;gt; Docker : cat id_ed25519.pub
Gradle --&amp;amp;gt; Dev : Clé publique SSH

Dev -&amp;amp;gt; Cloud : Enregistrement clé SSH\n(sur ollama.com/settings/keys)

== Authentification ==
Dev -&amp;amp;gt; Gradle : signInB
Gradle -&amp;amp;gt; Docker : ollama signin (interactif)
Dev &amp;amp;lt;-&amp;amp;gt; Cloud : Login navigateur (compte B)
Docker -&amp;amp;gt; Cloud : Échange token ⇔ Device Key
Gradle --&amp;amp;gt; Dev : Authentifié

== Vérification ==
Dev -&amp;amp;gt; Gradle : pullModelB
Gradle -&amp;amp;gt; Docker : ollama pull qwen3:0.6b
Gradle --&amp;amp;gt; Dev : Modèle pullé

Dev -&amp;amp;gt; Gradle : testOllamaB
Gradle -&amp;amp;gt; Docker : curl /v1/chat/completions
Gradle --&amp;amp;gt; Dev : ✓ Instance B OK

== Production ==
Dev -&amp;amp;gt; Gradle : pullAllProModels
Gradle -&amp;amp;gt; Docker : ollama pull deepseek-v4-pro:cloud
Gradle -&amp;amp;gt; Docker : ollama pull gemma4:31b-cloud
Gradle --&amp;amp;gt; Dev : Modèles Pro pullés

Dev -&amp;amp;gt; Gradle : statusOllamaAll
Gradle --&amp;amp;gt; Dev : ✓ Native ✓ Docker B
@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_なぜgradleプラグインとして作らないのか&amp;quot;&amp;gt;なぜGradleプラグインとして作らないのか？&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;正当な質問。これを抽出`build.gradle.kts`Gradleのスタンドアロンプラグインであると、以下のようなメリットがあります：プロジェクト間での再利用、宣言的な設定、DSL拡張。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;しかし、今は意味がありません。このビルドには複雑なビジネスロジックはなく、Docker と curl のコマンドをラップするだけです。拡張機能、ユニットテスト、公開を含む完全な Gradle プラグインをオーバーレイとして追加するのは、12 のユーティリティタスクに対して過大でしょう。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;Le &amp;lt;code&amp;gt;build.gradle.kts&amp;lt;/code&amp;gt; inline 必要なプロジェクトに存在します。他のところにコピーするのは簡単です。ある日私がそれに依存する3つのプロジェクトを持ったら、それをプラグインに変換します。今のところ、KISS。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;admonitionblock note&amp;quot;&amp;gt;
&amp;lt;table&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;icon&amp;quot;&amp;gt;
&amp;lt;i class=&amp;quot;fa icon-note&amp;quot; title=&amp;quot;ℹ️&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;
&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;三つ持っている日`build.gradle.kts`3つのプロジェクトで同じであることは、プラグインを抽出すべきだというシグナルです。それより前に、重複は抽象化よりもコストが低い。開発者の知恵。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/table&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_学んだ教訓&amp;quot;&amp;gt;学んだ教訓&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;olist arabic&amp;quot;&amp;gt;
&amp;lt;ol class=&amp;quot;arabic&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;Gradle は単なるビルドツールではない。&amp;lt;/strong&amp;gt;— 依存グラフエンジンは、恐るべきインフラストラクチャオーケストレーターとなる。&amp;lt;code&amp;gt;doLast&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;isIgnoreExitValue&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;dependsOn&amp;lt;/code&amp;gt;: これらの三つのプリミティブは、CI パイプラインと同じ信頼性で Docker コンテナを操作するのに十分です。&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;isIgnoreExitValue`は君の友達&amp;lt;/strong&amp;gt;— 理想的な世界で、&amp;lt;code&amp;gt;docker run`既存のコンテナー上で実行すると、エラー終了コードではなく警告が返されます。実際の世界では、あなたは`isIgnoreExitValue = true`そしてあなたは管理している診断で`doLast&amp;lt;/code&amp;gt;。&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;パラメータ化可能なタスクは曖昧さを殺す&amp;lt;/strong&amp;gt; — Un &amp;lt;code&amp;gt;pullModelB`ジェネリックと&amp;lt;/code&amp;gt;-Pmodel=&amp;amp;#8230;&amp;amp;#8203;`N 個の専門タスクを置き換えます。一つだけのタスク、一つだけのドキュメント、一つだけの動作。&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;runCatching`health checksのために&amp;lt;/strong&amp;gt;— Nのエンドポイントをテストするとき、最初のクラッシュが他のテストを妨げてはいけません。&amp;lt;code&amp;gt;runCatching&amp;lt;/code&amp;gt;+`getOrElse`エンドポイントごとに、そして診断は部分的な故障でも完全のままです。&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;helpOllama` タスクとしての実行可能なドキュメンテーション&amp;lt;/strong&amp;gt; — Un &amp;lt;code&amp;gt;println()`bien formaté&amp;lt;/code&amp;gt; が 3 段落の README を置き換えます。自己文書化されており、常に最新状態で、ターミナルを離れずにアクセスできます。&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ol&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_結論&amp;quot;&amp;gt;結論&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;手入力のDockerコマンドから、完全でバージョン管理され再利用可能なGradleワークフローに移行しました。12のタスクがライフサイクル全体をカバーします：プロビジョニング、アイデンティティ、サインイン、プル、テスト、診断、クリーニング。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;docker-compose + build.gradle.kts + opencode.json の組み合わせはきれいな三位一体を形成します：Dockerは隔離のため、Gradleはオーケストレーションのため、OpenCodeは消費のため。各レイヤーにはそれぞれの責任があり、いずれも他のレイヤーに干渉しません。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;次のステップは？ CI でライフサイクルを自動化し、一時的な開発環境で Ollama インスタンスを利用可能にすること。ただし、それは別の記事の話です。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_リソース&amp;quot;&amp;gt;リソース&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;https://docs.gradle.org/current/userguide/tutorial_using_tasks.html&amp;quot;&amp;gt;ユーザーマニュアル Gradle — タスク&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;https://docs.gradle.org/current/userguide/custom_tasks.html&amp;quot;&amp;gt;Gradle ユーザーマニュアル — カスタムタスク&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;https://hub.docker.com/r/ollama/ollama&amp;quot;&amp;gt;Docker Hub 上の Docker Ollama イメージ&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;https://kotlinlang.org/docs/gradle.html&amp;quot;&amp;gt;Gradle DSL Kotlin — ドキュメント&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;hr&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;em&amp;gt;記事が公開されました 2026-05-08&amp;lt;/em&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;</description>
        </item><item>
            <title>Dockerを使って同じマシンでOllama Proのサブスクリプションを2つ重ねる</title>
            <link >https://cheroliv.com/blog/2026/0120_cumuler_deux_abonnements_ollama_pro_docker_post.html</link>
            <pubDate>Fri, 8 May 2026 00:00:00 +0000</pubDate>
            <guid isPermaLink="false">blog/2026/0120_cumuler_deux_abonnements_ollama_pro_docker_post.html</guid>
            <description>&amp;lt;div id=&amp;quot;toc&amp;quot; class=&amp;quot;toc&amp;quot;&amp;gt;
&amp;lt;div id=&amp;quot;toctitle&amp;quot;&amp;gt;Table des matières&amp;lt;/div&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel1&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_はじめに&amp;quot;&amp;gt;はじめに&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_なぜ同じことを二度するのですか&amp;quot;&amp;gt;なぜ同じことを二度するのですか？&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_問題の核心_デバイスキー&amp;quot;&amp;gt;問題の核心 : デバイスキー&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_準備_手順ごと&amp;quot;&amp;gt;準備 — 手順ごと&amp;lt;/a&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel2&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_前提条件&amp;quot;&amp;gt;前提条件&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_ステップ_1ボリュームを作成&amp;quot;&amp;gt;ステップ 1：ボリュームを作成&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_ステップ_2_docker_コンテナーを起動&amp;quot;&amp;gt;ステップ 2 : Docker コンテナーを起動&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_ステップ_3_公開鍵を取得&amp;quot;&amp;gt;ステップ 3: 公開鍵を取得&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_ステップ4ollama_comでキーを登録&amp;quot;&amp;gt;ステップ4:Ollama.comでキーを登録&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_ステップ_5小さな無料モデルでテストする&amp;quot;&amp;gt;ステップ 5：小さな無料モデルでテストする&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_api_v1models_の罠&amp;quot;&amp;gt;API &amp;lt;code&amp;gt;/v1/models&amp;lt;/code&amp;gt; の罠&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_結果2つのセッション2つのアカウントゼロコンフリクト&amp;quot;&amp;gt;結果:2つのセッション、2つのアカウント、ゼロコンフリクト&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_学んだ教訓&amp;quot;&amp;gt;学んだ教訓&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_さらに進むために&amp;quot;&amp;gt;さらに進むために&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div id=&amp;quot;preamble&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;読了時間 : 14 minutes&amp;lt;/div&amp;gt;
&amp;lt;p&amp;gt;2つのProサブスクリプション、1台のマシン、1枚の銀行カード、そしてネットワーク競合ゼロ。Docker が 2 台 目の PC を 買わ ず に クラウド 推論 能力 を 2 倍 に する 方法 を 私 に 教え た。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_はじめに&amp;quot;&amp;gt;はじめに&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;私は数ヶ月間、Ollama Proを使ってOpenCodeのセッションにクラウドモデルを提供してきました。問題は、Proプランでも並行して複数のエージェントを起動するとすぐに*レートリミット*に達してしまうことです。明らかな解決策：もう一つのサブスクリプション。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;でも、これが悲劇だ。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;Ollamaは各マシンを一意のSSHキーで識別します — それが有名な*Device Key*です。同じOS上の2つのインスタンスは同じアイデンティティを共有し、同じデバイスに2つのProアカウントをリンクすることは不可能です。そしてあなたが予想するように、そのためだけにもう1台のラップトップを買うつもりはありませんでした。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;解決策 : 不正行為をする。 Ollama が異なる2台のマシンで動作していると誤認させる。実際には同じ CPU、同じ RAM、同じネットワーク接続を共有している。 Docker は完璧な隔離バブルを提供してくれる。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
!theme plain
skinparam BoxPadding 10
skinparam DefaultFontSize 12

left to right direction

node &amp;quot;物理的機械&amp;quot; {
  frame &amp;quot;Ollama インスタンス A (ネイティブ)&amp;quot; as Native {
    database &amp;quot;アイデンティティ\n/usr/share/ollama/.ollama/id_ed25519&amp;quot; as KeyA
    portin &amp;quot;API
:11434&amp;quot; as PortA
  }

  frame &amp;quot;Ollama インスタンス B (Docker)&amp;quot; as Docker {
    database &amp;quot;Identité\n~/ollama-b-data/id_ed25519&amp;quot; as KeyB
    portin &amp;quot;API\n:11435&amp;quot; as PortB
  }
}

cloud &amp;quot;Ollama クラウド&amp;quot; {
  actor &amp;quot;プロアカウント A
(メール 1)&amp;quot; as AccountA
  actor &amp;quot;プロ B アカウント
(email 2)&amp;quot; as AccountB
}

KeyA --&amp;amp;gt; AccountA : &amp;quot;SSHキー A&amp;quot;
KeyB --&amp;amp;gt; AccountB : &amp;quot;SSHキー B&amp;quot;
PortA --&amp;amp;gt; AccountA : &amp;quot;クエリー A&amp;quot;
PortB --&amp;amp;gt; AccountB : &amp;quot;リクエスト B&amp;quot;

note bottom of Docker
  Conteneur isolé : identité SSH distincte,
  port réseau distinct, volume persistant
end note
@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_なぜ同じことを二度するのですか&amp;quot;&amp;gt;なぜ同じことを二度するのですか？&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;私を精神病者扱いする前に、ユースケースを説明させてください。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;Proプランの単一のサブスクリプションだけで、私はモデルを起動することができます、たとえば`deepseek-v4-pro:cloud`OpenCode のセッションでは。問題が起きるのは、*二つ*のセッションを同時に使いたいときです。レートリミットのクォータにより、2番目のセッションが遅くなるか、完全に拒否されます。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;2つの独立したProサブスクリプションがあります：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;セッション OpenCode 1 → プロアカウント A`localhost:11434`)&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;セッション OpenCode 2 → プロアカウント B`localhost:11435`)&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;各セッションはそれぞれ独自の割り当てと独自のコンテキストを持ち、他のセッションに影響を与えません。これは人間のマルチプロセッシングです。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;admonitionblock important&amp;quot;&amp;gt;
&amp;lt;table&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;icon&amp;quot;&amp;gt;
&amp;lt;i class=&amp;quot;fa icon-important&amp;quot; title=&amp;quot;❗&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;
&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;Proサブスクリプション2つ = 異なるメールアドレス2つ。 同じ銀行カードは機能します — Ollamaの支払いシステムは、同じ支払い方法からの複数のサブスクリプションをブロックしません。 私は確認しました。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/table&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_問題の核心_デバイスキー&amp;quot;&amp;gt;問題の核心 : デバイスキー&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;Ollamaをインストールすると、アイデンティティディレクトリにed25519のSSHキーのペアが生成されます:&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;$ cat /usr/share/ollama/.ollama/id_ed25519.pub
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAI...&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;このキーはOllamaのサーバーにアップロードされます、の際に`ollama signin`. 彼女は言う：「このマシンは特定のProアカウントに属しています。」 もしあなたの2つのインスタンスが同じファイルを共有している場合`id_ed25519`彼らは同じアイデンティティを共有しています。ゲーム終了。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;パレード：2番目のインスタンスに独自のアイデンティティディレクトリを与える、Dockerボリューム内に隔離された&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_準備_手順ごと&amp;quot;&amp;gt;準備 — 手順ごと&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_前提条件&amp;quot;&amp;gt;前提条件&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;機能的な Ollama のネイティブインストール（公式スクリプト`curl | sh`)&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;Dockerがインストールされており、機能しています。&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;Portainer または docker-compose を使用したデプロイ&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;2つのOllamaアカウントと2つの異なるメールアドレス&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;私はバージョンを使いました`0.20.2`— 公式スクリプトによって提供されるものおよび対応するDockerイメージ。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_ステップ_1ボリュームを作成&amp;quot;&amp;gt;ステップ 1：ボリュームを作成&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;ホスト上の単純なディレクトリは、インスタンス B のアイデンティティの永続ボリュームとして機能します :&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;mkdir -p ~/ollama-b-data&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;このフォルダーはDockerコンテナーとしてマウントされます`/root/.ollama`、そこでオラマがアイデンティティキー、履歴、およびモデルを保存している&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_ステップ_2_docker_コンテナーを起動&amp;quot;&amp;gt;ステップ 2 : Docker コンテナーを起動&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-yaml hljs&amp;quot; data-lang=&amp;quot;yaml&amp;quot;&amp;gt;# docker-compose.yml
services:
  ollama-instance-b:
    image: ollama/ollama:0.20.2
    container_name: ollama-instance-b
    ports:
      - &amp;quot;11435:11434&amp;quot;
    volumes:
      - /home/cheroliv/ollama-b-data:/root/.ollama
    environment:
      - OLLAMA_HOST=0.0.0.0
    restart: always&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;ここで起きていること：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;港&amp;lt;strong&amp;gt;11435&amp;lt;/strong&amp;gt;ホストは &amp;amp;#8230;&amp;amp;#8203; にマッピングされます&amp;lt;strong&amp;gt;11434&amp;lt;/strong&amp;gt;コンテナの内部。それにより、Docker インスタンスはリッスンします。&amp;lt;code&amp;gt;:11435`ネイティブなインスタンスが居座っているにもかかわらず、衝突なく&amp;lt;/code&amp;gt;:11434`。&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;ボリューム`~/ollama-b-data`に取り付けられている`/root/.ollama`— ここで SSH のアイデンティティが保存されます。&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;`OLLAMA_HOST=0.0.0.0`コンテナが外部接続を受け入れることを許可する。&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;私はPortainerを使ってこのスタックをデプロイしましたが、単純な`docker compose up -d`同様に機能します。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_ステップ_3_公開鍵を取得&amp;quot;&amp;gt;ステップ 3: 公開鍵を取得&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;コンテナが初回起動時に空であるため、Ollama はボリューム内に新しい SSH キーペアを自動的に生成します。公開鍵を取得します：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;$ docker exec ollama-instance-b cat /root/.ollama/id_ed25519.pub
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIDDQ+dvnfmuo49q5O8LOlvgZ39SKORFw47ry9k4H2jPc&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;このキーがネイティブインスタンスのものと*異なる*ことを確認します:&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;# Instance native
$ cat /usr/share/ollama/.ollama/id_ed25519.pub
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGyF...(différente)

# Instance Docker
$ cat ~/ollama-b-data/id_ed25519.pub
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIDDQ...(différente)&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;�異なる二つの鍵、別々の二つのアイデンティティ。やり遂げた。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;admonitionblock note&amp;quot;&amp;gt;
&amp;lt;table&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;icon&amp;quot;&amp;gt;
&amp;lt;i class=&amp;quot;fa icon-note&amp;quot; title=&amp;quot;ℹ️&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;
&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;コンテナが再起動しても、ボリューム内のキーを &amp;lt;strong&amp;gt;再利用&amp;lt;/strong&amp;gt; します。アイデンティティは永続的です。Pro アカウントとの関連付けを失うことはありません。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/table&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_ステップ4ollama_comでキーを登録&amp;quot;&amp;gt;ステップ4:Ollama.comでキーを登録&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;https://ollama.com/settings/keys&amp;quot; class=&amp;quot;bare&amp;quot;&amp;gt;https://ollama.com/settings/keys&amp;lt;/a&amp;gt; の方向 → SSH キーを追加。 Docker インスタンスの公開鍵を貼り付けて確認します。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;次に、このアイデンティティを Pro B アカウントにリンクします :&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;$ docker exec -it ollama-instance-b ollama signin&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;ブラウザーが起動し、B アカウントのメールでログインし、トークンがコンテナの SSH キーに関連付けられます。すべてが問題ないことを確認します：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;$ docker exec -it ollama-instance-b ollama signin
User: cherolivpro&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_ステップ_5小さな無料モデルでテストする&amp;quot;&amp;gt;ステップ 5：小さな無料モデルでテストする&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;Proサブスクリプションの価格を挙げる前に、パイプが正常に機能していることを確認したい。接続を検証するために、ローカルの小さな無料モデルをpullする：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;$ docker exec ollama-instance-b ollama pull qwen3:0.6b
pulling manifest
pulling 7f4030143c1c: 100% ▕██████████████████▏ 522 MB
success

$ curl -s http://localhost:11435/api/tags
{&amp;quot;models&amp;quot;:[{&amp;quot;name&amp;quot;:&amp;quot;qwen3:0.6b&amp;quot;,&amp;quot;model&amp;quot;:&amp;quot;qwen3:0.6b&amp;quot;,...}]}&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;港`11435`答える、モデルは提供されている。 インスタンスBは生きている。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;安心したら、私は本当のクラウドProモデルのプルに移ります：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;$ docker exec ollama-instance-b ollama pull deepseek-v4-pro:cloud
pulling manifest
pulling 31c3059e137e: 100% ▕██████████████████▏  344 B
success&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;344オクテットはクラウドモデルのマニフェスト用です — 通常、推論はサーバーサイドで行われ、ローカルではありません。そしてこれが究極のテストです：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;$ curl -s http://localhost:11435/v1/chat/completions \
  -H &amp;quot;Content-Type: application/json&amp;quot; \
  -d &amp;#39;{&amp;quot;model&amp;quot;:&amp;quot;deepseek-v4-pro:cloud&amp;quot;,&amp;quot;messages&amp;quot;:[{&amp;quot;role&amp;quot;:&amp;quot;user&amp;quot;,&amp;quot;content&amp;quot;:&amp;quot;Dis bonjour en une phrase courte.&amp;quot;}]}&amp;#39;

{
  &amp;quot;id&amp;quot;: &amp;quot;chatcmpl-480&amp;quot;,
  &amp;quot;model&amp;quot;: &amp;quot;deepseek-v4-pro&amp;quot;,
  &amp;quot;choices&amp;quot;: [{
    &amp;quot;message&amp;quot;: { &amp;quot;content&amp;quot;: &amp;quot;Bonjour !&amp;quot; },
    &amp;quot;finish_reason&amp;quot;: &amp;quot;stop&amp;quot;
  }],
  &amp;quot;usage&amp;quot;: { &amp;quot;total_tokens&amp;quot;: 181 }
}&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;こんにちは、あなたにも、インスタンスB&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_api_v1models_の罠&amp;quot;&amp;gt;API &amp;lt;code&amp;gt;/v1/models&amp;lt;/code&amp;gt; の罠&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;愚かな細かいことで20分を無駄にした。 プロバイダーを設定したとき`ollama-b`OpenCode では、モデルセレクターに何も表示されませんでした。何も。まったく。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;理由は？ API`/v1/models`Bインスタンスが返した`{&amp;quot;object&amp;quot;:&amp;quot;list&amp;quot;,&amp;quot;data&amp;quot;:null}`代わりに`{&amp;quot;object&amp;quot;:&amp;quot;list&amp;quot;,&amp;quot;data&amp;quot;:[]}`どのモデルもプルされていなかったとき。値`null`OpenCode側のパースがクラッシュし、プロバイダーが表示されなかった。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;解決策：OpenCodeの設定でモデルを*明示的に*宣言し、動的な発見に依存しないようにする。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;~/.config/opencode/opencode.json&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-json hljs&amp;quot; data-lang=&amp;quot;json&amp;quot;&amp;gt;{
  &amp;quot;$schema&amp;quot;: &amp;quot;https://opencode.ai/config.json&amp;quot;,
  &amp;quot;provider&amp;quot;: {
    &amp;quot;ollama&amp;quot;: {
      &amp;quot;npm&amp;quot;: &amp;quot;@ai-sdk/openai-compatible&amp;quot;,
      &amp;quot;name&amp;quot;: &amp;quot;Ollama (local)&amp;quot;,
      &amp;quot;options&amp;quot;: { &amp;quot;baseURL&amp;quot;: &amp;quot;http://localhost:11434/v1&amp;quot; },
      &amp;quot;models&amp;quot;: {
        &amp;quot;gemma4:e2b&amp;quot;: { &amp;quot;name&amp;quot;: &amp;quot;Gemma 4 E2B (local)&amp;quot; }
      }
    },
    &amp;quot;ollama-b&amp;quot;: {
      &amp;quot;npm&amp;quot;: &amp;quot;@ai-sdk/openai-compatible&amp;quot;,
      &amp;quot;name&amp;quot;: &amp;quot;Ollama Instance B (Docker)&amp;quot;,
      &amp;quot;options&amp;quot;: { &amp;quot;baseURL&amp;quot;: &amp;quot;http://localhost:11435/v1&amp;quot; },
      &amp;quot;models&amp;quot;: {
        &amp;quot;qwen3:0.6b&amp;quot;: { &amp;quot;name&amp;quot;: &amp;quot;Qwen3 0.6B (B)&amp;quot; },
        &amp;quot;deepseek-v4-pro:cloud&amp;quot;: { &amp;quot;name&amp;quot;: &amp;quot;DeepSeek V4 Pro (B)&amp;quot; }
      }
    }
  }
}&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;この明示的な宣言により、OpenCodeはすぐにプロバイダーBとそのモデルを認識します。セッションを再起動すると、セレクター`/models`両方のインスタンスを横に並べて表示します。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;admonitionblock tip&amp;quot;&amp;gt;
&amp;lt;table&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;icon&amp;quot;&amp;gt;
&amp;lt;i class=&amp;quot;fa icon-tip&amp;quot; title=&amp;quot;💡&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;
&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;あなたの provider custom が表示されない場合の中に`/models`, ターミナルの再起動に3時間も費やさないでください。モデルを手動で宣言してください 中に`opencode.json`— それは問題を瞬時に解決します。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/table&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_結果2つのセッション2つのアカウントゼロコンフリクト&amp;quot;&amp;gt;結果:2つのセッション、2つのアカウント、ゼロコンフリクト&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;最終的に、私はOpenCodeのセッションを2つ同時に起動できます ：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-text hljs&amp;quot; data-lang=&amp;quot;text&amp;quot;&amp;gt;Session 1 → /models → Ollama (local) → deepseek-v4-pro:cloud → Compte A
Session 2 → /models → Ollama Instance B (Docker) → deepseek-v4-pro:cloud → Compte B&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;各セッションはそれぞれ独自のクォータとレートリミットを持ち、互いに干渉しません。同じマシン、同じブルーカード、でもメールアドレスは2つ異なります。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;そして最高なのは？ Dockerコンテナは`restart: always`. システムの再起動後も手動介入なしで生き残ります。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_学んだ教訓&amp;quot;&amp;gt;学んだ教訓&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;olist arabic&amp;quot;&amp;gt;
&amp;lt;ol class=&amp;quot;arabic&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;Dockerは全てを隔離する、アイデンティティさえも&amp;lt;/strong&amp;gt;— ボリュームのシンプルなバインドマウントで、コンテナに独自のSSHキーのセットを与えることができ、Ollamaの目には物理的に異なるマシンと区別がつかなくなります。&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;2通のメール、同じCB&amp;lt;/strong&amp;gt;Ollamaは同じ支払い方法からの複数のサブスクリプションをブロックしません。メールアドレスのみが異なる必要があります。&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;支払う前に無料でテスト&amp;lt;/strong&amp;gt; — Un &amp;lt;code&amp;gt;ollama pull qwen3:0.6b&amp;lt;/code&amp;gt; (modèle libre, 522 Mo) permet de valider toute la chaîne réseau sans débourser un centime. Vous validez le plomberie d&amp;amp;#8217;abord, vous activez le Pro ensuite.&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;/v1/models` と &amp;lt;code&amp;gt;data: null&amp;lt;/code&amp;gt; は OpenCode を壊します&amp;lt;/strong&amp;gt;— カスタムプロバイダーを設定するときに`&amp;quot;models&amp;quot;: {}`, OpenCodeはAPIを通じてモデルの発見を試みます。APIが応答した場合`data: null`, プロバイダーが表示されません。モデルを明示的に宣言してください。&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;2つのアカウント、それは人間のマルチプロセッシングです&amp;lt;/strong&amp;gt;— Proアカウント = アクティブなOpenCodeセッション。2つのアカウント = 2つの並列セッション。複数のGradleプロジェクトを同時に扱う人にとって、これはゲームチェンジャー。&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ol&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_さらに進むために&amp;quot;&amp;gt;さらに進むために&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;https://ollama.com/settings/keys&amp;quot;&amp;gt;Ollama Settings — SSHキーの管理&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;https://docs.ollama.com/&amp;quot;&amp;gt;Ollama 公式ドキュメント&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;https://hub.docker.com/r/ollama/ollama&amp;quot;&amp;gt;Docker Hub上のDocker Ollamaイメージ&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;https://opencode.ai/docs/providers/#ollama&amp;quot;&amp;gt;OpenCode — 構成プロバイダー Ollama&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;hr&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;em&amp;gt;記事は 2026-05-08 に公開されました&amp;lt;/em&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;</description>
        </item><item>
            <title>XubuntuでKittyターミナルをインストールし、Zshをデフォルトシェルとして設定する</title>
            <link >https://cheroliv.com/blog/2025/0080_kitty_term_post.html</link>
            <pubDate>Thu, 7 May 2026 00:00:00 +0000</pubDate>
            <guid isPermaLink="false">blog/2025/0080_kitty_term_post.html</guid>
            <description>&amp;lt;div id=&amp;quot;toc&amp;quot; class=&amp;quot;toc&amp;quot;&amp;gt;
&amp;lt;div id=&amp;quot;toctitle&amp;quot;&amp;gt;Sommaire&amp;lt;/div&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel1&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_kitty_と_zsh_を選ぶ理由は&amp;quot;&amp;gt;Kitty と Zsh を選ぶ理由は？&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_システムの前提条件&amp;quot;&amp;gt;システムの前提条件&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_kittyのダウンロードとインストール&amp;quot;&amp;gt;Kittyのダウンロードとインストール&amp;lt;/a&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel2&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_インストールスクリプトをダウンロード&amp;quot;&amp;gt;インストールスクリプトをダウンロード&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_シンボリックリンクの作成&amp;quot;&amp;gt;シンボリックリンクの作成&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_xubuntuへのkittyの統合&amp;quot;&amp;gt;XubuntuへのKittyの統合&amp;lt;/a&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel2&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_デスクトップのファイルをコピー&amp;quot;&amp;gt;デスクトップのファイルをコピー&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_デスクトップファイルを編集する&amp;quot;&amp;gt;デスクトップファイルを編集する&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_kitty_を既定のターミナルとして関連付ける_オプション&amp;quot;&amp;gt;Kitty を既定のターミナルとして関連付ける (オプション)&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_zshのインストール&amp;quot;&amp;gt;Zshのインストール&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_zshをデフォルトのシェルとして設定&amp;quot;&amp;gt;Zshをデフォルトのシェルとして設定&amp;lt;/a&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel2&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_グローバルメソッド_すべての端末向け&amp;quot;&amp;gt;グローバルメソッド (すべての端末向け)&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_kitty専用のメソッド&amp;quot;&amp;gt;Kitty専用のメソッド&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_zshの設定オプション&amp;quot;&amp;gt;Zshの設定（オプション）&amp;lt;/a&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel2&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_zshrc_ファイルを作成する&amp;quot;&amp;gt;.zshrc ファイルを作成する&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_最小構成の例&amp;quot;&amp;gt;最小構成の例&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_ワークフロー全体のサマリー&amp;quot;&amp;gt;ワークフロー全体のサマリー&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_最終確認&amp;quot;&amp;gt;最終確認&amp;lt;/a&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel2&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_設定ファイルを開く&amp;quot;&amp;gt;�📂 設定ファイルを開く&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_️_追加または変更_font_size&amp;quot;&amp;gt;�🖋️ 追加または変更 `font_size&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_保存して_kitty_を再起動&amp;quot;&amp;gt;💾 保存して Kitty を再起動&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_動的調整_一時ズーム&amp;quot;&amp;gt;✅ 動的調整 (一時ズーム)&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_oh_my_zshのインストールと設定&amp;quot;&amp;gt;Oh My Zshのインストールと設定&amp;lt;/a&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel2&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_oh_my_zshのインストール&amp;quot;&amp;gt;Oh My Zshのインストール&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_テーマを変更する&amp;quot;&amp;gt;テーマを変更する&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_検証&amp;quot;&amp;gt;�検証&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_ユースケース図&amp;quot;&amp;gt;ユースケース図&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_kitty_で透明性を有効にする&amp;quot;&amp;gt;Kitty で透明性を有効にする&amp;lt;/a&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel2&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_透明性のための前提条件&amp;quot;&amp;gt;透明性のための前提条件&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_kitty_conf_での透明度の設定&amp;quot;&amp;gt;kitty.conf での透明度の設定&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_kitty_を再起動&amp;quot;&amp;gt;Kitty を再起動&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_可能な補足&amp;quot;&amp;gt;可能な補足&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_シーケンス図_kittyの透明度付き初期化&amp;quot;&amp;gt;シーケンス図 - Kittyの透明度付き初期化&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_既知の制限&amp;quot;&amp;gt;既知の制限&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_ビープ音audible_bellを無効にする&amp;quot;&amp;gt;ビープ音（audible bell）を無効にする&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_kittyのアップデート&amp;quot;&amp;gt;Kittyのアップデート&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_参照&amp;quot;&amp;gt;参照&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_結論&amp;quot;&amp;gt;結論&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div id=&amp;quot;preamble&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;このガイドは、Xubuntu 上でターミナル &amp;lt;strong&amp;gt;kitty&amp;lt;/strong&amp;gt; をインストールする方法、正しく設定する方法、そしてデフォルトシェルとして &amp;lt;strong&amp;gt;bash&amp;lt;/strong&amp;gt; を &amp;lt;strong&amp;gt;zsh&amp;lt;/strong&amp;gt; に置き換える方法をステップバイステップで説明します。 kitty プロジェクトはこちらから利用できます: &amp;lt;a href=&amp;quot;https://github.com/kovidgoyal/kitty&amp;quot; class=&amp;quot;bare&amp;quot;&amp;gt;https://github.com/kovidgoyal/kitty&amp;lt;/a&amp;gt;.&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;em&amp;gt;&amp;lt;em&amp;gt;_ Kittyは、要求の厳しい開発者に特に適した、モダンで高速かつ設定可能なターミナルです。 &amp;lt;/em&amp;gt;_&amp;lt;/em&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_kitty_と_zsh_を選ぶ理由は&amp;quot;&amp;gt;Kitty と Zsh を選ぶ理由は？&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;Kittyは次の点で特徴があります：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;GPUアクセラレーションによる高いパフォーマンス,&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;1つのテキストファイルに完全に基づく設定,&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;フォントとリガチャの優れたサポートです。&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;Zshはそれに対して、強力なインタラクティブなシェルを提供します：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;インテリジェントな補完、&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;カスタマイズ可能なプロンプト,&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;bashとの高い互換性&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;Kitty と Zsh を組み合わせることで、生産的で美的な環境を得られます。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
title シンプルなアーキテクチャ Kitty + Zsh
actor User

User --&amp;amp;gt; Kitty : Lance le terminal
Kitty --&amp;amp;gt; Zsh : Initialise le shell interactif
Zsh --&amp;amp;gt; System : Interagit avec le système (fichiers, commandes)
@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;admonitionblock note&amp;quot;&amp;gt;
&amp;lt;table&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;icon&amp;quot;&amp;gt;
&amp;lt;i class=&amp;quot;fa icon-note&amp;quot; title=&amp;quot;Note&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;
&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;このガイドは意図的にスクリプトによるインストールとXubuntuに限定されています。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/table&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_システムの前提条件&amp;quot;&amp;gt;システムの前提条件&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;始める前に、必要なものを確認してください：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;Xubuntu インストール済み&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;インターネットへのアクセス,&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;スクリプトを起動するための機能的なbashシェル。&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;環境を確認してください：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;uname -a
lsb_release -a&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_kittyのダウンロードとインストール&amp;quot;&amp;gt;Kittyのダウンロードとインストール&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;Kittyは公式スクリプトを使ってインストールすることを推奨し、そのスクリプトはファイルを配置します。&amp;lt;code&amp;gt;~/.local/kitty.app&amp;lt;/code&amp;gt;。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;admonitionblock important&amp;quot;&amp;gt;
&amp;lt;table&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;icon&amp;quot;&amp;gt;
&amp;lt;i class=&amp;quot;fa icon-important&amp;quot; title=&amp;quot;Important&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;
&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;この方法はパッケージマネージャに依存しない（なしの`apt`).&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/table&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_インストールスクリプトをダウンロード&amp;quot;&amp;gt;インストールスクリプトをダウンロード&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;次のコマンドを実行してください：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;curl -L https://sw.kovidgoyal.net/kitty/installer.sh | sh /dev/stdin&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;このコマンドは実行します：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;バイナリのダウンロード,&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;抽出 中に`~/.local/kitty.app`,&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;シンボリックリンクの作成。&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
title Kittyのダウンロードとインストール
start
:curl -L installer.sh;
:sh /dev/stdin;
:Décompression dans ~/.local/kitty.app;
:create symlinks;
stop
@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_シンボリックリンクの作成&amp;quot;&amp;gt;シンボリックリンクの作成&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;呼び出すことができるように`kitty`ターミナルから、シンボリックリンクを作成してください：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;ln -s ~/.local/kitty.app/bin/kitty ~/.local/bin/kitty&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;追加してください`~/.local/bin`まだPATHに追加していない場合は :&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;echo &amp;#39;export PATH=&amp;quot;$HOME/.local/bin:$PATH&amp;quot;&amp;#39; &amp;amp;gt;&amp;amp;gt; ~/.zshrc
source ~/.zshrc&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;インストールを確認できます：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;kitty --version&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_xubuntuへのkittyの統合&amp;quot;&amp;gt;XubuntuへのKittyの統合&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;Kitty がアプリケーションメニューに表示されるように：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_デスクトップのファイルをコピー&amp;quot;&amp;gt;デスクトップのファイルをコピー&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;ファイルをコピーしてください`.desktop`提供 :&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;cp ~/.local/kitty.app/share/applications/kitty.desktop ~/.local/share/applications/&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_デスクトップファイルを編集する&amp;quot;&amp;gt;デスクトップファイルを編集する&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;ファイルを編集してください：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;nano ~/.local/share/applications/kitty.desktop&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;次の行を確認または編集してください：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-none hljs&amp;quot;&amp;gt;[Desktop Entry]
Version=1.0
Type=Application
Name=Kitty Terminal
Comment=Fast GPU-based terminal emulator
Exec=/home/$USER/.local/kitty.app/bin/kitty
Icon=kitty
Categories=System;TerminalEmulator;&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;置き換えて`YOURUSER`あなたのユーザー名で。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
title XubuntuメニューへのKittyの統合プロセス
start
:Copier .desktop;
:Editer les chemins;
:Sauvegarder;
:Menu Applications;
stop
@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_kitty_を既定のターミナルとして関連付ける_オプション&amp;quot;&amp;gt;Kitty を既定のターミナルとして関連付ける (オプション)&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;Kitty がデフォルトのターミナルとして起動されるようにする :&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;sudo update-alternatives --install /usr/bin/x-terminal-emulator x-terminal-emulator ~/.local/kitty.app/bin/kitty 50
sudo update-alternatives --config x-terminal-emulator&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;選択して`kitty`提案されたメニューに。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_zshのインストール&amp;quot;&amp;gt;Zshのインストール&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;Zsh がまだインストールされていない場合は、実行してください :&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;sudo apt install zsh&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;インストールを確認してください：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-none hljs&amp;quot;&amp;gt;zsh --version&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_zshをデフォルトのシェルとして設定&amp;quot;&amp;gt;Zshをデフォルトのシェルとして設定&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;シェルをグローバルに変更するか、Kitty内だけで変更することができます。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_グローバルメソッド_すべての端末向け&amp;quot;&amp;gt;グローバルメソッド (すべての端末向け)&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;絶対パスを特定してください：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;which zsh&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;一般的に`/usr/bin/zsh`。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;デフォルトのシェルを変更：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;chsh -s /usr/bin/zsh&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;ログアウトして、もう一度ログインしてください。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
title シェルのグローバルな変更
actor User

User --&amp;amp;gt; Bash : Session actuelle
User --&amp;amp;gt; System : chsh -s /usr/bin/zsh
System --&amp;amp;gt; &amp;quot;/etc/passwd&amp;quot; : Modifie le shell
note right of &amp;quot;/etc/passwd&amp;quot; : Shell par défaut mis à jour
@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_kitty専用のメソッド&amp;quot;&amp;gt;Kitty専用のメソッド&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;Kitty のシェルだけを変更したい場合は、設定ファイルを編集してください :&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;nano ~/.config/kitty/kitty.conf&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;この行を追加してください:&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-text hljs&amp;quot; data-lang=&amp;quot;text&amp;quot;&amp;gt;shell zsh&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;Kittyを保存して再起動してください。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_zshの設定オプション&amp;quot;&amp;gt;Zshの設定（オプション）&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;Zshをカスタマイズする：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_zshrc_ファイルを作成する&amp;quot;&amp;gt;.zshrc ファイルを作成する&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;touch ~/.zshrc
nano ~/.zshrc&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_最小構成の例&amp;quot;&amp;gt;最小構成の例&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;export ZSH_THEME=&amp;quot;robbyrussell&amp;quot;
export PATH=&amp;quot;$HOME/.local/bin:$PATH&amp;quot;
alias ll=&amp;quot;ls -la&amp;quot;&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_ワークフロー全体のサマリー&amp;quot;&amp;gt;ワークフロー全体のサマリー&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;以下の図は、プロセス全体をまとめています：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
title インストールと設定のワークフロー
start
:Téléchargement script Kitty;
:Installation dans ~/.local;
:Création symlink;
:Ajout ~/.local/bin au PATH;
if (Zsh installé ?) then (non)
  :sudo apt install zsh;
endif
:Configurer Kitty.desktop;
:Optionnel - changer terminal par défaut;
:Optionnel - chsh -s /usr/bin/zsh;
stop
@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_最終確認&amp;quot;&amp;gt;最終確認&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;キティを起動してください：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;kitty&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;あなたはそれが見えるはずです`zsh`アクティブです :&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;echo $SHELL&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;期待される結果：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;/usr/bin/zsh&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;フォントサイズを変更する&amp;lt;strong&amp;gt;キティ&amp;lt;/strong&amp;gt;, パラメータを調整する必要があります`font_size`設定ファイル内で。以下は詳細な手順です。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_設定ファイルを開く&amp;quot;&amp;gt;�📂 設定ファイルを開く&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;メインの構成ファイルは通常、次の場所にあります：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;~/.config/kitty/kitty.conf&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;このファイルがまだ存在しない場合は、作成することができます。 例 :&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;nano ~/.config/kitty/kitty.conf&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_️_追加または変更_font_size&amp;quot;&amp;gt;�🖋️ 追加または変更 `font_size&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;次のディレクティブを追加し、すでに存在している場合はそれを変更してください：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-text hljs&amp;quot; data-lang=&amp;quot;text&amp;quot;&amp;gt;font_size 14.0&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;ここ`14.0`希望のサイズに対応します。小数値であれば任意の値を入力できます。たとえば`12.0`, &amp;lt;code&amp;gt;15.5&amp;lt;/code&amp;gt;, など&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_保存して_kitty_を再起動&amp;quot;&amp;gt;💾 保存して Kitty を再起動&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;保存 (&amp;lt;code&amp;gt;Ctrl + O&amp;lt;/code&amp;gt;、そして`Entrée`)そして離れて(&amp;lt;code&amp;gt;Ctrl + X&amp;lt;/code&amp;gt;) あなたが使っている場合`nano`.&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;Kitty のすべてのウィンドウを閉じ、ターミナルを再起動して変更を反映させてください。&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_動的調整_一時ズーム&amp;quot;&amp;gt;✅ 動的調整 (一時ズーム)&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;一時的にズームイン/ズームアウトしたいが設定を変更しない場合は、デフォルトのキーボードショートカットを使用してください：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;フォントサイズを増やす&amp;lt;/strong&amp;gt; :&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;code&amp;gt;Ctrl + Shift + =&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;フォントサイズを小さくする&amp;lt;/strong&amp;gt;:&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;code&amp;gt;Ctrl + Shift + -&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;サイズをリセット&amp;lt;/strong&amp;gt;：&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;code&amp;gt;Ctrl + Shift + Backspace&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;これらの設定は端末を閉じた後も保持されません。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_oh_my_zshのインストールと設定&amp;quot;&amp;gt;Oh My Zshのインストールと設定&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;Zshがインストールされ、デフォルトシェルとして設定された後、*Oh My Zsh*で環境を豊かにすることができます。Zshの構成管理フレームワークである*Oh My Zsh*は、以下を提供します：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;プロンプト用のテーマのコレクション,&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;多数のプラグイン,&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;設定の明確な組織&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_oh_my_zshのインストール&amp;quot;&amp;gt;Oh My Zshのインストール&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;Zsh がアクティブであることを確認してください：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;zsh --version&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;必要なら、起動してください：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;zsh&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;その後、公式インストールスクリプトをダウンロードして実行してください：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;sh -c &amp;quot;$(curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)&amp;quot;&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;このスクリプト：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;フォルダーを作成して`~/.oh-my-zsh`,&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;ファイルを保存する場合があります`~/.zshrc`,&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;自動的に新しいプロンプトをアクティベートします。&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_テーマを変更する&amp;quot;&amp;gt;テーマを変更する&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;設定ファイルを開いてください：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;nano ~/.zshrc&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;変数を変更してください`ZSH_THEME`別のテーマを選択するために（例えば`agnoster`) :&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;ZSH_THEME=&amp;quot;agnoster&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;設定を保存し、再読み込みしてください：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;source ~/.zshrc&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_検証&amp;quot;&amp;gt;�検証&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;Kitty を起動して、プロンプトが確かに変わったことを確認してください。 次のコマンドを実行して、Oh My Zsh がアクティブであることを確認できます：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;echo $ZSH&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;結果は次のように似ているはずです：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;/home/あなたのユーザー/.oh-my-zsh&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_ユースケース図&amp;quot;&amp;gt;ユースケース図&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
title ユースケース Oh My Zshのインストールと使い方
actor Utilisateur as User

package &amp;quot;Kittyターミナル&amp;quot; {
  component &amp;quot;Zsh シェル&amp;quot; as Zsh
}

component &amp;quot;Oh My Zsh フレームワーク&amp;quot; as OhMyZsh

User --&amp;amp;gt; Kitty : Lance Kitty
Kitty --&amp;amp;gt; Zsh : Initialise Zsh
Zsh --&amp;amp;gt; OhMyZsh : Charge configuration (~/.zshrc, thèmes, plugins)
User --&amp;amp;gt; OhMyZsh : Personnalise le thème et les plugins

@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_kitty_で透明性を有効にする&amp;quot;&amp;gt;Kitty で透明性を有効にする&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;Kittyの最も気に入られた機能の1つは、ターミナルの背景に*透明性*を追加できることです。これにより、基盤となる環境（ウィンドウ、デスクトップなど）をわずかに見ることができ、これはマルチタスク時に特に役立ちます。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_透明性のための前提条件&amp;quot;&amp;gt;透明性のための前提条件&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;Kittyにおける透明性は&amp;lt;strong&amp;gt;ウィンドウコンポーザー&amp;lt;/strong&amp;gt;グラフィカル環境によって使用される。 Xubuntu (XFCEベース)では、次のことを確認してください：&amp;lt;strong&amp;gt;構成が有効になっています&amp;lt;/strong&amp;gt;。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;確認 :&amp;lt;/div&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;右クリック &amp;amp;gt; デスクトップ &amp;amp;gt; 設定 &amp;amp;gt;&amp;lt;strong&amp;gt;ウィンドウマネージャーの設定&amp;lt;/strong&amp;gt;,&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;タブ&amp;lt;strong&amp;gt;作曲家&amp;lt;/strong&amp;gt;: 「&amp;lt;strong&amp;gt;&amp;quot;コンポジットを有効にする&amp;lt;/strong&amp;gt;&amp;quot;」チェックボックスはチェックされている必要があります。&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
title Use Case - Kitty で透明度を有効にする
actor Utilisateur

rectangle &amp;quot;グラフィカル環境 (XFCE/Xubuntu)&amp;quot; {
  usecase &amp;quot;合成を有効にする&amp;quot; as UC1
}

rectangle &amp;quot;Kittyターミナル&amp;quot; {
  usecase &amp;quot;kitty.conf で透明度を設定する&amp;quot; as UC2
}

Utilisateur --&amp;amp;gt; UC1
Utilisateur --&amp;amp;gt; UC2

@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_kitty_conf_での透明度の設定&amp;quot;&amp;gt;kitty.conf での透明度の設定&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;設定ファイルを開いてください`~/.config/kitty/kitty.conf`:&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;nano ~/.config/kitty/kitty.conf&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;次の行を追加または変更してください：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-conf hljs&amp;quot; data-lang=&amp;quot;conf&amp;quot;&amp;gt;background_opacity 0.85&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;このパラメータは、次の範囲の値を受け付けます：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;code&amp;gt;1.0&amp;lt;/code&amp;gt;→ 不透明（透明性なし），&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;code&amp;gt;0.0&amp;lt;/code&amp;gt;→ 完全に 透明 （使用できない），&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;中間値のような`0.90`, &amp;lt;code&amp;gt;0.75&amp;lt;/code&amp;gt;, など&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;良いビジュアルな妥協点は通常、&amp;lt;code&amp;gt;0.85&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;0.95&amp;lt;/code&amp;gt;。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_kitty_を再起動&amp;quot;&amp;gt;Kitty を再起動&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;Kittyのすべてのインスタンスを閉じ、変更が反映されるように新しいウィンドウを再起動してください。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;kitty&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_可能な補足&amp;quot;&amp;gt;可能な補足&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;カスタム端末の背景を使用している場合、背景色に透明度を設定することもできます（RGBA）：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-conf hljs&amp;quot; data-lang=&amp;quot;conf&amp;quot;&amp;gt;background #1e1e2eff&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;最後のコンポーネント(&amp;lt;code&amp;gt;ff&amp;lt;/code&amp;gt;) 示す 不透明度 (で`00` à &amp;lt;code&amp;gt;ff&amp;lt;/code&amp;gt;).&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_シーケンス図_kittyの透明度付き初期化&amp;quot;&amp;gt;シーケンス図 - Kittyの透明度付き初期化&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
title 透明付きのKitty起動シーケンス
actor User
participant &amp;quot;キティ&amp;quot; as Kitty
participant &amp;quot;XFCE コンポジター&amp;quot; as XFCE
participant &amp;quot;GPU/ウィンドウマネージャ&amp;quot; as WM

User -&amp;amp;gt; Kitty : Lance Kitty
Kitty -&amp;amp;gt; kitty.conf : Lit configuration
Kitty -&amp;amp;gt; XFCE : Vérifie composition activée
XFCE --&amp;amp;gt; Kitty : Composition = active
Kitty -&amp;amp;gt; WM : Demande allocation fenêtrée transparente
WM --&amp;amp;gt; Kitty : OK (rendu avec alpha &amp;amp;lt; 1)
Kitty -&amp;amp;gt; User : Affiche terminal translucide

@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_既知の制限&amp;quot;&amp;gt;既知の制限&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;admonitionblock warning&amp;quot;&amp;gt;
&amp;lt;table&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;icon&amp;quot;&amp;gt;
&amp;lt;i class=&amp;quot;fa icon-warning&amp;quot; title=&amp;quot;Warning&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;
&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;透明度が機能しない場合は： - XFCE コンポジタは無効になっています、 - 互換性のないウィンドウマネージャが使用されています, - あなたはKittyをバックグラウンドで透明度サポートなしの*tmux*モードで使用しています。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/table&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_ビープ音audible_bellを無効にする&amp;quot;&amp;gt;ビープ音（audible bell）を無効にする&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;デフォルトでは、Kitty は間違ったコマンドが入力されたときや、ターミナル イベントがトリガーされたときに &amp;lt;strong&amp;gt;bip&amp;lt;/strong&amp;gt; 音を鳴らします。この音はすぐに鬱陶しくなることがあります、特に激しい開発環境では。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;この動作を無効にするには、ファイルに次のディレクティブを追加してください。&amp;lt;code&amp;gt;~/.config/kitty/kitty.conf&amp;lt;/code&amp;gt;(Note: Since there is no French source text provided, the translation is empty.)&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-conf hljs&amp;quot; data-lang=&amp;quot;conf&amp;quot;&amp;gt;audible_bell no&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;admonitionblock note&amp;quot;&amp;gt;
&amp;lt;table&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;icon&amp;quot;&amp;gt;
&amp;lt;i class=&amp;quot;fa icon-note&amp;quot; title=&amp;quot;Note&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;
&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;ビープ音の代わりに、*ビジュアルフィードバック*も有効にできます :&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-conf hljs&amp;quot; data-lang=&amp;quot;conf&amp;quot;&amp;gt;visual_bell yes&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/table&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_kittyのアップデート&amp;quot;&amp;gt;Kittyのアップデート&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;Kittyがスクリプトでインストールされ、パッケージマネージャーではないため、アップデートは公式インストールスクリプトを再実行することで行われます。これにより、最新バージョンをダウンロードし、既存のインストールをアップデートすることができますで`~/.local/kitty.app`.&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;admonitionblock note&amp;quot;&amp;gt;
&amp;lt;table&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;icon&amp;quot;&amp;gt;
&amp;lt;i class=&amp;quot;fa icon-note&amp;quot; title=&amp;quot;Note&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;
&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;接尾辞`.app`道の中`~/.local/kitty.app`これは、KittyのLinuxへの公式スクリプトによるインストールの慣習であり、macOSとの独占的な互換性を示すものではありません。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/table&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;admonitionblock important&amp;quot;&amp;gt;
&amp;lt;table&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;icon&amp;quot;&amp;gt;
&amp;lt;i class=&amp;quot;fa icon-important&amp;quot; title=&amp;quot;Important&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;
&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;アップデートコマンドを実行する前に、ホームディレクトリにいることを確認してください。 (&amp;lt;code&amp;gt;~&amp;lt;/code&amp;gt;)&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/table&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;以下のコマンドをホームディレクトリから実行してください。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;curl -L https://sw.kovidgoyal.net/kitty/installer.sh | sh /dev/stdin&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;このスクリプトは次のように処理します：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;新しいバージョンのバイナリをダウンロード&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;ファイルを抽出する`~/.local/kitty.app`。&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;必要に応じてシンボリックリンクを更新してください。&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;アップデート後は、すべての Kitty インスタンスを閉じてから再起動することをお勧めします。これにより、新しいバージョンが正しく反映されることを確認できます。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_参照&amp;quot;&amp;gt;参照&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;カスタマイズをさらに詳しく知りたい場合は、公式ドキュメントを参照してください：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;Kitty : &amp;lt;a href=&amp;quot;https://sw.kovidgoyal.net/kitty/&amp;quot; class=&amp;quot;bare&amp;quot;&amp;gt;https://sw.kovidgoyal.net/kitty/&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;https://sw.kovidgoyal.net/kitty/conf/#opt-kitty.background_opacity&amp;quot; class=&amp;quot;bare&amp;quot;&amp;gt;https://sw.kovidgoyal.net/kitty/conf/#opt-kitty.background_opacity&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;https://sw.kovidgoyal.net/kitty/conf/#opt-kitty.audible_bell&amp;quot; class=&amp;quot;bare&amp;quot;&amp;gt;https://sw.kovidgoyal.net/kitty/conf/#opt-kitty.audible_bell&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;Zsh : &amp;lt;a href=&amp;quot;https://zsh.sourceforge.io/&amp;quot; class=&amp;quot;bare&amp;quot;&amp;gt;https://zsh.sourceforge.io/&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;GitHub: &amp;lt;a href=&amp;quot;https://github.com/kovidgoyal/kitty&amp;quot; class=&amp;quot;bare&amp;quot;&amp;gt;https://github.com/kovidgoyal/kitty&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;Zsh: &amp;lt;a href=&amp;quot;https://zsh.sourceforge.io/&amp;quot; class=&amp;quot;bare&amp;quot;&amp;gt;https://zsh.sourceforge.io/&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;https://ohmyz.sh/&amp;quot; class=&amp;quot;bare&amp;quot;&amp;gt;https://ohmyz.sh/&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;https://github.com/ohmyzsh/ohmyzsh/wiki&amp;quot; class=&amp;quot;bare&amp;quot;&amp;gt;https://github.com/ohmyzsh/ohmyzsh/wiki&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;https://docs.xfce.org/xfce/xfwm4/compositor&amp;quot; class=&amp;quot;bare&amp;quot;&amp;gt;https://docs.xfce.org/xfce/xfwm4/compositor&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_結論&amp;quot;&amp;gt;結論&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;あなたは今：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;現代的で高性能なターミナル (Kitty)&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;強力でカスタマイズ可能なシェル（Zsh）&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;システムパッケージに依存しないきれいな構成&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;見た目も機能も優れた、Oh My Zsh を装備したターミナル&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;</description>
        </item><item>
            <title>DGX Spark vs Cloud vs Abonnements LLM — Le Benchmark Économique Qui Tue le Rêve du Hardware Local</title>
            <link >https://cheroliv.com/blog/2026/0119_benchmark_dgx_spark_vs_cloud_abonnement_llm_post.html</link>
            <pubDate>Wed, 6 May 2026 00:00:00 +0000</pubDate>
            <guid isPermaLink="false">blog/2026/0119_benchmark_dgx_spark_vs_cloud_abonnement_llm_post.html</guid>
            <description>&amp;lt;div id=&amp;quot;toc&amp;quot; class=&amp;quot;toc&amp;quot;&amp;gt;
&amp;lt;div id=&amp;quot;toctitle&amp;quot;&amp;gt;Table des matières&amp;lt;/div&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel1&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_le_contexte_un_marché_qui_a_basculé&amp;quot;&amp;gt;Le Contexte : Un Marché Qui a Basculé&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_le_panel_des_options&amp;quot;&amp;gt;Le Panel des Options&amp;lt;/a&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel2&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_ce_que_jai_exclu_et_pourquoi&amp;quot;&amp;gt;Ce Que J&amp;amp;#8217;ai Exclu (et Pourquoi)&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_inférence_simple_la_mort_du_hardware_local&amp;quot;&amp;gt;Inférence Simple : La Mort du Hardware Local&amp;lt;/a&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel2&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_le_calcul&amp;quot;&amp;gt;Le Calcul&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_même_avec_un_usage_intensif&amp;quot;&amp;gt;Même avec un Usage Intensif&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_fine_tuning_le_cloud_est_imbattable&amp;quot;&amp;gt;Fine-Tuning : Le Cloud Est Imbattable&amp;lt;/a&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel2&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_le_coût_réel_dun_fine_tune&amp;quot;&amp;gt;Le Coût Réel d&amp;amp;#8217;un Fine-Tune&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_les_acteurs_spécialisés&amp;quot;&amp;gt;Les Acteurs Spécialisés&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_la_seule_vraie_raison_la_souveraineté_des_données&amp;quot;&amp;gt;La Seule Vraie Raison : La Souveraineté des Données&amp;lt;/a&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel2&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_le_vrai_calcul_de_la_confidentialité&amp;quot;&amp;gt;Le Vrai Calcul de la Confidentialité&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_synthèse_la_matrice_de_décision&amp;quot;&amp;gt;Synthèse : La Matrice de Décision&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_le_cas_particulier_labonnement_pro_face_aux_modèles_chinois&amp;quot;&amp;gt;Le Cas Particulier : L&amp;amp;#8217;Abonnement Pro Face aux Modèles Chinois&amp;lt;/a&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel2&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_pourquoi_les_modèles_chinois_changent_tout&amp;quot;&amp;gt;Pourquoi les Modèles Chinois Changent Tout&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_ce_que_ça_veut_dire_pour_le_hardware&amp;quot;&amp;gt;Ce Que Ça Veut Dire pour le Hardware&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_et_huawei&amp;quot;&amp;gt;Et Huawei ?&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_conclusion_le_luxe_de_la_proximité&amp;quot;&amp;gt;Conclusion : Le Luxe de la Proximité&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div id=&amp;quot;preamble&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;temps de lecture : 14 minutes&amp;lt;/div&amp;gt;
&amp;lt;p&amp;gt;NVIDIA vend le DGX Spark comme un « supercalculateur IA de bureau » à $4 699. Ollama propose ses modèles cloud à $20/mois. Un H100 se loue $1.38/h chez Vast.ai. Et les modèles chinois open-source — DeepSeek, Qwen, GLM — sont disponibles partout, gratuitement, sans avoir à acheter une carte. Alors, ce Spark, il sert à quoi au juste ? J&amp;amp;#8217;ai fait les maths.&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;dlist&amp;quot;&amp;gt;
&amp;lt;dl&amp;gt;
&amp;lt;dt class=&amp;quot;hdlist1&amp;quot;&amp;gt;toc&amp;lt;/dt&amp;gt;
&amp;lt;dd&amp;gt;
&amp;lt;p&amp;gt;[]&amp;lt;/p&amp;gt;
&amp;lt;/dd&amp;gt;
&amp;lt;/dl&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_le_contexte_un_marché_qui_a_basculé&amp;quot;&amp;gt;Le Contexte : Un Marché Qui a Basculé&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;En mai 2026, le paysage de l&amp;amp;#8217;IA a radicalement changé par rapport à l&amp;amp;#8217;annonce du DGX Spark au CES 2025. Trois forces ont convergé pour rendre le hardware local de plus en plus difficile à justifier :&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;L&amp;amp;#8217;effondrement des prix du cloud GPU&amp;lt;/strong&amp;gt; : un H100 se loue entre $1.38 et $3/h, contre $5-8/h il y a 18 mois&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;L&amp;amp;#8217;explosion des modèles chinois open-source&amp;lt;/strong&amp;gt; : DeepSeek-V4, Qwen-3, GLM-5 sont compétitifs avec les modèles occidentaux, disponibles gratuitement&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;La montée des plateformes d&amp;amp;#8217;inférence managée&amp;lt;/strong&amp;gt; : Ollama, Groq, Together AI proposent des API à des tarifs agressifs, avec des paliers gratuits généreux&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;Le DGX Spark, annoncé à $2 999 puis monté à $4 699, arrive dans un monde qui n&amp;amp;#8217;a plus besoin de lui.&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_le_panel_des_options&amp;quot;&amp;gt;Le Panel des Options&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;Voici les solutions disponibles en mai 2026 pour faire tourner des LLMs, de la plus légère à la plus lourde :&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;table class=&amp;quot;tableblock frame-all grid-all stretch&amp;quot;&amp;gt;
&amp;lt;colgroup&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.5%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.5%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.5%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.5%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.5%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.5%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.5%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.5%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.5%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.5%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.5%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.5%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.5%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.5%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.5%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.5%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.5%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.5%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.5%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.5%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.5%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.5%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.5%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.5%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.5%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.5%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.5%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.5%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.5%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.5%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.5%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.5%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.5%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.5%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.5%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.5%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.5%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.5%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.5%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.5%;&amp;quot;&amp;gt;
&amp;lt;/colgroup&amp;gt;
&amp;lt;tbody&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;Option&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;Coût&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;VRAM / Capacité&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;Modèles accessibles&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;Contrainte principale&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;Ollama Free&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;$0/mois&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;Cloud léger&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;Tous modèles publics&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;Usage limité, 1 modèle simultané&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;Claude Pro&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;$20/mois (~$240/an)&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;N/A (API fermée)&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;Claude 4.x uniquement&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;Modèle unique, pas d&amp;amp;#8217;open-source&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;Ollama Pro&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;$20/mois (~$200/an)&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;Cloud medium&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;Tous modèles publics&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;3 modèles simultanés max&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;Ollama Max&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;$100/mois (~$1 200/an)&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;Cloud heavy&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;Tous modèles publics&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;10 modèles simultanés&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;Cloud GPU (H100)&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;$1.38-3/h&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;80 Go HBM&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;Tous modèles, fine-tuning&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;Facturation horaire, setup requis&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;DGX Spark&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;$4 699 (achat)&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;128 Go unifié&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;Tous modèles &amp;amp;lt;128 Go&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;Lent (~10x moins qu&amp;amp;#8217;un H100), fixe&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;Mac Studio M3 Ultra&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;~$5 000+&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;192 Go unifié&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;Tous modèles &amp;amp;lt;192 Go&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;Pas CUDA, écosystème MLX&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/tbody&amp;gt;
&amp;lt;/table&amp;gt;
&amp;lt;div class=&amp;quot;admonitionblock tip&amp;quot;&amp;gt;
&amp;lt;table&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;icon&amp;quot;&amp;gt;
&amp;lt;i class=&amp;quot;fa icon-tip&amp;quot; title=&amp;quot;💡&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;
&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;Les prix cloud GPU cités sont ceux de Vast.ai et RunPod en mai 2026 — du spot/on-demand, pas du réservé. Les prix des hyperscalers (AWS, GCP, Azure) restent 2-3x plus élevés.&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/table&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_ce_que_jai_exclu_et_pourquoi&amp;quot;&amp;gt;Ce Que J&amp;amp;#8217;ai Exclu (et Pourquoi)&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;J&amp;amp;#8217;ai volontairement exclu les options suivantes de ce benchmark :&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;API OpenAI / Anthropic / Google&amp;lt;/strong&amp;gt; : le sujet ici est de faire tourner des modèles &amp;lt;strong&amp;gt;open-source&amp;lt;/strong&amp;gt; qu&amp;amp;#8217;on peut choisir, fine-tuner, et ne pas être dépendant d&amp;amp;#8217;un vendor unique&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;Huawei Ascend / Atlas&amp;lt;/strong&amp;gt; : Huawei ne commercialise pas d&amp;amp;#8217;équivalent desktop au DGX Spark. La gamme Ascend (910C, 910D) et Atlas (300I Duo, 350) est orientée datacenter — cartes PCIe, serveurs rack — pas des boîtiers compacts prêts à brancher. La puce Ascend 910C embarque 128 Go HBM mais c&amp;amp;#8217;est une puce serveur, pas un système autonome. L&amp;amp;#8217;Atlas 300I Duo offre 96 Go pour ~$1 400 mais nécessite une machine hôte&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_inférence_simple_la_mort_du_hardware_local&amp;quot;&amp;gt;Inférence Simple : La Mort du Hardware Local&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;Commençons par le cas d&amp;amp;#8217;usage le plus commun : chatter avec un LLM, faire du code review, générer du texte. Pas de fine-tuning, pas de batch processing, juste de l&amp;amp;#8217;inférence interactive.&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_le_calcul&amp;quot;&amp;gt;Le Calcul&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;Un DGX Spark à $4 699. Divisons par le coût annuel de chaque abonnement :&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div id=&amp;quot;diag-breakeven&amp;quot; class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
skinparam backgroundColor #FEFEFE
skinparam defaultTextAlignment center

title Seuil de Rentabilité — DGX Spark ($4 699) vs Abonnements

rectangle &amp;quot;DGX Spark\n$4 699&amp;quot; as spark #FFCDD2

rectangle &amp;quot;Ollama Pro\n$200/an&amp;quot; as opro #C8E6C9
rectangle &amp;quot;Claude Pro\n$240/an&amp;quot; as cpro #C8E6C9
rectangle &amp;quot;Ollama Max\n$1 200/an&amp;quot; as omax #FFF9C4
rectangle &amp;quot;Cloud H100\n$3/h × 10h/sem&amp;quot; as cloud #BBDEFB

spark --&amp;amp;gt; opro : 23.5 années ⏳
spark --&amp;amp;gt; cpro : 19.6 années ⏳
spark --&amp;amp;gt; omax : 3.9 années
spark --&amp;amp;gt; cloud : 3.0 années (à 10h/semaine, intermittent)

note bottom of spark
  Sans compter l&amp;#39;électricité (~$150/an)
  Sans compter l&amp;#39;obsolescence hardware
  Sans compter qu&amp;#39;il est 10x plus lent
end note

@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;Le verdict est brutal. Pour de l&amp;amp;#8217;inférence :&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;Ollama Pro&amp;lt;/strong&amp;gt; : il vous faudrait &amp;lt;strong&amp;gt;23 ans&amp;lt;/strong&amp;gt; pour amortir un DGX Spark. Le Spark sera obsolète depuis 20 ans.&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;Ollama Max&amp;lt;/strong&amp;gt; : &amp;lt;strong&amp;gt;4 ans&amp;lt;/strong&amp;gt; — à condition d&amp;amp;#8217;utiliser le Spark 24/7, ce que personne ne fait&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;Claude Pro&amp;lt;/strong&amp;gt; : même problème, &amp;lt;strong&amp;gt;20 ans&amp;lt;/strong&amp;gt; pour du single-model fermé&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;em&amp;gt;&amp;lt;em&amp;gt;_ La promesse du « supercalculateur IA de bureau » se heurte à une réalité comptable élémentaire : $4 699 / $20 par mois = jamais rentable pour un usage individuel. &amp;lt;/em&amp;gt;_&amp;lt;/em&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_même_avec_un_usage_intensif&amp;quot;&amp;gt;Même avec un Usage Intensif&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;Prenons le pire scénario pour le cloud : vous faites tourner un H100 8h/jour, 5 jours/semaine, 52 semaines/an.&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;8 × 5 × 52 = 2 080 heures/an&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;2 080 × $2/h (prix moyen spot H100) = &amp;lt;strong&amp;gt;$4 160/an&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;Le Spark ($4 699) est rentabilisé en &amp;lt;strong&amp;gt;13 mois&amp;lt;/strong&amp;gt;. Sauf que :&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;olist arabic&amp;quot;&amp;gt;
&amp;lt;ol class=&amp;quot;arabic&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;Le H100 est &amp;lt;strong&amp;gt;~10x plus rapide&amp;lt;/strong&amp;gt; que le GB10 du Spark. Vous faites en 1h ce que le Spark fait en 10h. Pour le même volume de travail, le H100 vous coûte $416/an, pas $4 160.&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;Le H100 a 80 Go HBM à 3.35 To/s de bande passante. Le Spark a 128 Go LPDDR5X à 273 Go/s. Pour les gros modèles, la bande passante compte plus que la capacité.&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ol&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;admonitionblock important&amp;quot;&amp;gt;
&amp;lt;table&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;icon&amp;quot;&amp;gt;
&amp;lt;i class=&amp;quot;fa icon-important&amp;quot; title=&amp;quot;❗&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;
&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;Comparer 1h de H100 à 1h de Spark n&amp;amp;#8217;a pas de sens. Le H100 fait le travail 10x plus vite. Le vrai coût cloud pour un workload donné est donc ~10x inférieur au calcul naïf basé sur les heures.&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/table&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_fine_tuning_le_cloud_est_imbattable&amp;quot;&amp;gt;Fine-Tuning : Le Cloud Est Imbattable&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;L&amp;amp;#8217;argument classique des défenseurs du Spark : « oui mais pour le fine-tuning, c&amp;amp;#8217;est différent ».&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;Non, ça ne l&amp;amp;#8217;est pas.&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_le_coût_réel_dun_fine_tune&amp;quot;&amp;gt;Le Coût Réel d&amp;amp;#8217;un Fine-Tune&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;Un fine-tune LoRA/QLoRA sur Unsloth d&amp;amp;#8217;un modèle 7B :&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;~2-3h sur un H100 = &amp;lt;strong&amp;gt;$5 à $9&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;Même chose sur le Spark = &amp;lt;strong&amp;gt;20-30h&amp;lt;/strong&amp;gt; (10x plus lent), bloque la machine&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;Avec les $4 699 du Spark, vous pouvez financer :&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;~500 à ~900 fine-tunes&amp;lt;/strong&amp;gt; en cloud H100&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;Ou &amp;lt;strong&amp;gt;~23 ans&amp;lt;/strong&amp;gt; d&amp;amp;#8217;Ollama Pro&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;Ou &amp;lt;strong&amp;gt;~4 ans&amp;lt;/strong&amp;gt; d&amp;amp;#8217;Ollama Max&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;Et pour des modèles plus gros (70B+) :&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;Le Spark avec ses 128 Go peut charger un 70B en Q4 — mais le fine-tune sera extrêmement lent&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;Un H100 avec 80 Go peut fine-tuner un 70B en QLoRA 4-bit en quelques heures&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;Pour du full fine-tune, il faut du multi-GPU de toute façon — le Spark est hors course&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_les_acteurs_spécialisés&amp;quot;&amp;gt;Les Acteurs Spécialisés&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;En 2026, des plateformes comme Unsloth, Modal, Replicate, et Together AI proposent du fine-tuning serverless :&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;Pas de gestion de GPU&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;Pas de configuration d&amp;amp;#8217;environnement&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;Paiement à la minute&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;Optimisations intégrées (flash attention, quantization automatique)&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div id=&amp;quot;diag-fine-tuning-cost&amp;quot; class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
skinparam backgroundColor #FEFEFE
skinparam defaultTextAlignment center
title &amp;amp;lt;size:20&amp;amp;gt;Coût d&amp;#39;un Fine-Tune LoRA 7B — Comparaison&amp;amp;lt;/size&amp;amp;gt;
note as N
|= Option |= Coût par fine-tune |= Fine-tunes possibles avec $4 699 |
| **Replicate** | $3-5 | ~1 000 |
| **Modal (serverless)** | $2-4 | ~1 500 |
| **Unsloth + Vast.ai H100** | $5-9 | ~500-900 |
| **Together AI** | $4-8 | ~600-1 000 |
| **DGX Spark** | « gratuit » mais 20-30h | ∞ (en théorie) |
end note
note bottom
  Le Spark est « gratuit » par fine-tune seulement si votre temps vaut $0/h
  et que vous n&amp;#39;avez pas besoin de la machine pour autre chose pendant 30h
end note
@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_la_seule_vraie_raison_la_souveraineté_des_données&amp;quot;&amp;gt;La Seule Vraie Raison : La Souveraineté des Données&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;Après avoir éliminé l&amp;amp;#8217;inférence, le fine-tuning, et le rapport qualité/prix — que reste-t-il au Spark ?&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;La confidentialité absolue.&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;Pas la confidentialité « je ne veux pas que mes prompts soient lus par un employé d&amp;amp;#8217;OpenAI ». Ça, c&amp;amp;#8217;est un faux problème en 2026 : Ollama, Groq, et la plupart des providers respectables ont des politiques de zéro log et zéro rétention.&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;La vraie confidentialité, c&amp;amp;#8217;est :&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;Air-gap réglementaire&amp;lt;/strong&amp;gt; : défense, diplomatie, santé — les données ne peuvent &amp;lt;strong&amp;gt;physiquement&amp;lt;/strong&amp;gt; pas quitter le bâtiment&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;Données propriétaires critiques&amp;lt;/strong&amp;gt; : code source d&amp;amp;#8217;un produit non publié, secrets industriels, algorithmes de trading&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;Résilience réseau&amp;lt;/strong&amp;gt; : l&amp;amp;#8217;IA doit continuer à fonctionner même si Internet tombe&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;admonitionblock caution&amp;quot;&amp;gt;
&amp;lt;table&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;icon&amp;quot;&amp;gt;
&amp;lt;i class=&amp;quot;fa icon-caution&amp;quot; title=&amp;quot;🔒&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;
&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;Mais soyons honnêtes : quel pourcentage des acheteurs de DGX Spark est réellement dans ce cas ? 1% ? Le reste, c&amp;amp;#8217;est du « nice to have » transformé en dépense à $4 699.&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/table&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_le_vrai_calcul_de_la_confidentialité&amp;quot;&amp;gt;Le Vrai Calcul de la Confidentialité&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;Pour un usage individuel :&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;Ollama Pro&amp;lt;/strong&amp;gt; ($20/mois) + modèles open source chinois = solution pragmatique&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;Si un prompt fuit chez Ollama, il se noie dans les millions de requêtes quotidiennes. C&amp;amp;#8217;est la goutte d&amp;amp;#8217;eau dans l&amp;amp;#8217;océan.&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;Le risque réel n&amp;amp;#8217;est pas la fuite d&amp;amp;#8217;un prompt — c&amp;amp;#8217;est l&amp;amp;#8217;entraînement non consenti sur vos données. Et ça, les providers sérieux l&amp;amp;#8217;interdisent contractuellement.&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;em&amp;gt;&amp;lt;em&amp;gt;_ La peur de « distiller son prompt dans le LLM » est un niveau de propagation d&amp;amp;#8217;information personnel tellement dilué qu&amp;amp;#8217;il relève plus de l&amp;amp;#8217;anxiété que de la menace réelle. À l&amp;amp;#8217;échelle industrielle, c&amp;amp;#8217;est différent. Mais à l&amp;amp;#8217;échelle individuelle, c&amp;amp;#8217;est du bruit. &amp;lt;/em&amp;gt;_&amp;lt;/em&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_synthèse_la_matrice_de_décision&amp;quot;&amp;gt;Synthèse : La Matrice de Décision&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div id=&amp;quot;diag-decision-matrix&amp;quot; class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
skinparam backgroundColor #FEFEFE
skinparam defaultTextAlignment center

title Quelle Solution IA Choisir en 2026 ?

start

:Quel est votre besoin principal ?;

switch (Besoin)

case (Inférence interactive occasionnelle)
  :**Ollama Free**\n$0/mois, tous modèles open-source;
  stop

case (Inférence quotidienne, code review, dev)
  :**Ollama Pro** ($20/mois)\nAccès à tous les modèles open-source\nDeepSeek, Qwen, GLM, Llama, Mistral;
  stop

case (Agents IA, multi-modèles, usage intensif)
  :Contexte &amp;amp;gt; 30K tokens ?;

  if (Oui) then
    :**Ollama Max** ($100/mois)\n10 modèles simultanés\nContexte long sans dégradation;
    stop
  else (Non)
    :**Cloud GPU H100 spot** ($1.38–3/h)\n+ Unsloth/Modal pour fine-tuning\nPerformance brute maximale;
    stop
  endif

case (Fine-tuning régulier)
  :**Vast.ai H100 + Unsloth** ($5–9/fine-tune)\nou **Together AI / Modal** (serverless)\n500+ fine-tunes pour le prix d’un Spark;
  stop

case (Air-gap obligatoire)
  :Données classifiées ?;

  if (Oui) then
    :**DGX Spark** ou **Mac Studio M3 Ultra**\nSeul cas où le hardware local est justifié\n(pas économiquement — politiquement);
    stop
  else (Non)
    :Retour au cloud : pas de besoin d’air-gap;
    stop
  endif

endswitch

@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;table class=&amp;quot;tableblock frame-all grid-all stretch&amp;quot;&amp;gt;
&amp;lt;colgroup&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.2222%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.2222%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.2222%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.2222%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.2222%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.2222%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.2222%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.2222%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.2222%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.2222%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.2222%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.2222%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.2222%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.2222%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.2222%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.2222%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.2222%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.2222%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.2222%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.2222%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.2222%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.2222%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.2222%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.2222%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.2222%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.2222%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.2222%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.2222%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.2222%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.2222%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.2222%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.2222%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.2222%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.2222%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.2222%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.2222%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.2222%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.2222%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.2222%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.2222%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.2222%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.2222%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.2222%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.2222%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.2232%;&amp;quot;&amp;gt;
&amp;lt;/colgroup&amp;gt;
&amp;lt;tbody&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;Critère&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;Ollama Free&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;Ollama Pro&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;Cloud GPU H100&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;DGX Spark&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;Inférence&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;✅ Limitée&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;✅ Confortable&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;✅ Overkill&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;⚠️ Lent&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;Fine-tuning&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;❌&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;❌&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;✅ Imbattable&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;⚠️ Possible mais lent&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;Coût annuel&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;$0&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;$200&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;Variable (~$416-2 080*)&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;$4 699 upfront&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;Confidentialité&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;⚠️ Cloud US&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;⚠️ Cloud US&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;⚠️ Cloud US (variable)&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;✅ Totale&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;Maintenance&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;Aucune&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;Aucune&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;Setup unique&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;Électricité, mises à jour&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;Obsolescence&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;Aucune&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;Aucune&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;Aucune&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;3-5 ans&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;Écosystème logiciel&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;Tous modèles open&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;Tous modèles open&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;Tous modèles open&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;CUDA (mais lent)&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;Veridict&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;Occasionnel&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;Recommandé&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;Pros/Recherche&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;Air-gap uniquement&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/tbody&amp;gt;
&amp;lt;/table&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;em&amp;gt;*Variable selon volume de travail ; avec vitesse H100 ~10x &amp;amp;gt; Spark, le coût effectif pour un workload donné est bas.&amp;lt;/em&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_le_cas_particulier_labonnement_pro_face_aux_modèles_chinois&amp;quot;&amp;gt;Le Cas Particulier : L&amp;amp;#8217;Abonnement Pro Face aux Modèles Chinois&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;Un point mérite d&amp;amp;#8217;être souligné : la combinaison &amp;lt;strong&amp;gt;Ollama Pro à $20/mois + modèles chinois open-source&amp;lt;/strong&amp;gt; est probablement le meilleur rapport qualité/prix de l&amp;amp;#8217;histoire de l&amp;amp;#8217;IA grand public.&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_pourquoi_les_modèles_chinois_changent_tout&amp;quot;&amp;gt;Pourquoi les Modèles Chinois Changent Tout&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;DeepSeek-V4-Pro&amp;lt;/strong&amp;gt; : 1.6T params, CSA+HCA, 1M contexte, compétitif avec Claude 4 et GPT-5 pour le code&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;Qwen-3&amp;lt;/strong&amp;gt; : 235B, 256K contexte, excellent en français et en raisonnement&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;GLM-5.1&amp;lt;/strong&amp;gt; : 744B, MLA+DSA, 200K contexte, taillé pour l&amp;amp;#8217;agentique&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;Tous disponibles sur Ollama. Tous open-source (licences permissives). Tous utilisables sans restriction via un abonnement à $20/mois.&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;admonitionblock tip&amp;quot;&amp;gt;
&amp;lt;table&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;icon&amp;quot;&amp;gt;
&amp;lt;i class=&amp;quot;fa icon-tip&amp;quot; title=&amp;quot;💡&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;
&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;Avec Ollama Pro, vous avez accès à ~5 modèles « frontier » open-source pour le prix d&amp;amp;#8217;un seul modèle fermé (Claude Pro). La valeur est tellement asymétrique que ça en devient presque absurde.&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/table&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_ce_que_ça_veut_dire_pour_le_hardware&amp;quot;&amp;gt;Ce Que Ça Veut Dire pour le Hardware&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;Si le meilleur rapport qualité/prix est un abonnement cloud à $20/mois, le hardware local devient un choix de &amp;lt;strong&amp;gt;confort&amp;lt;/strong&amp;gt; ou de &amp;lt;strong&amp;gt;principe&amp;lt;/strong&amp;gt; — pas un choix économique.&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;Un DGX Spark à $4 699, c&amp;amp;#8217;est l&amp;amp;#8217;équivalent de :&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;235 mois d&amp;amp;#8217;Ollama Pro&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;23 jeux AAA jour de sortie&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;4 MacBook Air M4&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;Un an de loyer d&amp;amp;#8217;un T2 à Lyon&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;Pour du calcul. Lent.&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_et_huawei&amp;quot;&amp;gt;Et Huawei ?&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;Puisque la question m&amp;amp;#8217;a été posée pendant mes recherches : non, Huawei ne commercialise pas d&amp;amp;#8217;équivalent au DGX Spark.&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;Ce qui existe :&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;Ascend 910C&amp;lt;/strong&amp;gt; : 128 Go HBM, 800 TFLOPS FP16 — mais c&amp;amp;#8217;est une puce serveur, pas un desktop&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;Atlas 300I Duo&amp;lt;/strong&amp;gt; : 96 Go LPDDR4X, carte PCIe à ~$1 400 — nécessite un hôte&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;Atlas 350&amp;lt;/strong&amp;gt; : 112 Go HBM, 1.56 PFLOPS FP4 — accélérateur datacenter, pas un boîtier compact&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;Huawei reste focalisé sur le marché des serveurs et des centres de données. Pour un boîtier compact « prêt à brancher » avec 120+ Go de VRAM, le DGX Spark (128 Go unifié) et le Mac Studio M3 Ultra (192 Go unifié) sont les seules options en 2026. Et pour l&amp;amp;#8217;instant, aucun constructeur chinois n&amp;amp;#8217;a annoncé de produit équivalent dans ce format.&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_conclusion_le_luxe_de_la_proximité&amp;quot;&amp;gt;Conclusion : Le Luxe de la Proximité&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;Le DGX Spark n&amp;amp;#8217;est pas un mauvais produit. C&amp;amp;#8217;est un mauvais investissement pour 99% des acheteurs potentiels.&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div id=&amp;quot;diag-verdict&amp;quot; class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
skinparam backgroundColor #FEFEFE
skinparam defaultTextAlignment center

title Le Paysage IA en 2026 — Qui Domine ?

left to right direction

package &amp;quot;Usage Personnel / PME&amp;quot; #C8E6C9 {
  rectangle &amp;quot;🏆 Ollama Pro\n$20/mois&amp;quot; as pro
  rectangle &amp;quot;Ollama Free\n$0/mois&amp;quot; as free
  rectangle &amp;quot;Cloud GPU spot\n$1-3/h&amp;quot; as spot
}

package &amp;quot;Usage Intensif / Pro&amp;quot; #FFF9C4 {
  rectangle &amp;quot;🏆 Ollama Max\n$100/mois&amp;quot; as max
  rectangle &amp;quot;🏆 Cloud GPU dédié\n$2-4/h&amp;quot; as dedicated
  rectangle &amp;quot;Modal / Together AI\nServerless&amp;quot; as serverless
}

package &amp;quot;Air-Gap Obligatoire&amp;quot; #FFCDD2 {
  rectangle &amp;quot;DGX Spark\n$4 699&amp;quot; as spark
  rectangle &amp;quot;Mac Studio M3U\n~$5 000&amp;quot; as mac
}

note bottom of spark
  1% des cas d&amp;#39;usage — défense,
  santé réglementée, secrets
  industriels critiques
end note

@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;em&amp;gt;&amp;lt;em&amp;gt;_ Acheter un DGX Spark en 2026, c&amp;amp;#8217;est comme acheter un serveur mail en 2010 : techniquement possible, philosophiquement satisfaisant, économiquement absurde pour un individu. &amp;lt;/em&amp;gt;_&amp;lt;/em&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;Le calcul est simple, et il ne ment pas :&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;$0&amp;lt;/strong&amp;gt; pour chatter avec DeepSeek sur Ollama Free&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;$200/an&amp;lt;/strong&amp;gt; pour bosser sérieusement avec Ollama Pro&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;$5-9&amp;lt;/strong&amp;gt; pour un fine-tune ponctuel sur cloud GPU&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;$4 699&amp;lt;/strong&amp;gt; pour&amp;amp;#8230;&amp;amp;#8203; l&amp;amp;#8217;expérience d&amp;amp;#8217;avoir un boîtier NVIDIA sur son bureau ?&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;Le marché a tranché. Les abonnements cloud et les modèles open-source chinois ont gagné la bataille du prix. Le hardware local survit dans les niches réglementaires, pas dans les bureaux des développeurs.&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;em&amp;gt;&amp;lt;em&amp;gt;_ Le DGX Spark n&amp;amp;#8217;est pas un outil rentable. C&amp;amp;#8217;est un statement. « Je veux mon IA chez moi, pas dans le cloud de quelqu&amp;amp;#8217;un d&amp;amp;#8217;autre. » C&amp;amp;#8217;est respectable. Mais en 2026, quand Ollama te donne DeepSeek-V4-Pro dans le cloud pour $20/mois, c&amp;amp;#8217;est surtout un statement qui coûte très cher. &amp;lt;/em&amp;gt;_&amp;lt;/em&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;hr&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;Cet article est issu d&amp;amp;#8217;une conversation avec mon agent IA sur la pertinence économique du DGX Spark, croisée avec une veille marché sur les prix cloud GPU (Vast.ai, RunPod), les grilles tarifaires Ollama/Claude, et l&amp;amp;#8217;écosystème des modèles chinois open-source. Les prix cités sont ceux de mai 2026 — ils auront probablement encore baissé quand vous lirez ces lignes.&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;</description>
        </item><item>
            <title>LLMガバナンスマトリクス — なぜあなたのAIのセキュリティはツリー構造から始まるのか</title>
            <link >https://cheroliv.com/blog/2026/0118_matrice_gouvernance_llm_zone_acces_workspace_post.html</link>
            <pubDate>Mon, 4 May 2026 00:00:00 +0000</pubDate>
            <guid isPermaLink="false">blog/2026/0118_matrice_gouvernance_llm_zone_acces_workspace_post.html</guid>
            <description>&amp;lt;div id=&amp;quot;toc&amp;quot; class=&amp;quot;toc&amp;quot;&amp;gt;
&amp;lt;div id=&amp;quot;toctitle&amp;quot;&amp;gt;Table des matières&amp;lt;/div&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel1&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_問題プロンプトエンジニアリングは砂の城&amp;quot;&amp;gt;問題：プロンプトエンジニアリングは砂の城&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_私の回答44の行列&amp;quot;&amp;gt;私の回答：4×4の行列&amp;lt;/a&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel2&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_五つのゾーン空間的次元_rgpd&amp;quot;&amp;gt;五つのゾーン（空間的次元 — RGPD）&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_認識論的分類第二次元&amp;quot;&amp;gt;認識論的分類（第二次元）&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_llmはこの行列をどのように消費するか&amp;quot;&amp;gt;LLMはこの行列をどのように消費するか&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_実装_型付き_gradle_タスク&amp;quot;&amp;gt;実装 : 型付き Gradle タスク&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_なぜこれがマニフェストで単なるスペックではないのか&amp;quot;&amp;gt;なぜこれがマニフェストで、単なるスペックではないのか&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_完全なカスケード_ブレインダンプからブログ記事へ&amp;quot;&amp;gt;完全なカスケード — ブレインダンプからブログ記事へ&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_賛成反対&amp;quot;&amp;gt;�賛成/反対&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_結論_ファイルを整理しプロンプトは整理しない&amp;quot;&amp;gt;結論 : ファイルを整理し、プロンプトは整理しない&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_参照&amp;quot;&amp;gt;参照&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div id=&amp;quot;preamble&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;読了時間 : 14 minutes&amp;lt;/div&amp;gt;
&amp;lt;p&amp;gt;何ヶ月も、エージェントのガバナンスルールを積み重ねてきました。ファイル EAGER、LAZYなチェックリスト、6段階のセッション終了プロトコル。 しかし、未解決の質問が残っていた：&amp;lt;strong&amp;gt;LLMは何を知っているのか&amp;lt;/strong&amp;gt; ファイルに対して何をすることができる権利がある？*&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;回答はプロンプトにありません。 それはファイルシステムにあります。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;これが回答を利用可能にするアーキテクチャ仕様 — la &amp;lt;strong&amp;gt;LLMガバナンスマトリクス&amp;lt;/strong&amp;gt;。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_問題プロンプトエンジニアリングは砂の城&amp;quot;&amp;gt;問題：プロンプトエンジニアリングは砂の城&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;ファイルをLLMに与えるとき、私たちはすべてを与える。コンテンツ、はい — さらに、セーフガードが欠如していることも。LLM はこのファイルに何が含まれているかわからない 秘密、憶測の意見、またはクローズドソースのコードです。それをインデックスします。 要約し、引用し、他のデータと混ぜ合わせ — そして潜在的に 公開のエンベディングまたはユーザーのレスポンスに掲載する。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;クラシックなもの、つまりプロンプトです：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-text hljs&amp;quot; data-lang=&amp;quot;text&amp;quot;&amp;gt;&amp;quot;Tu es un assistant sécurisé. Ne divulgue jamais d&amp;#39;informations confidentielles.
Si tu détectes un secret, ignore-le. Si tu détectes une opinion, ne la répète pas.&amp;quot;&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;このプロンプトには3つの問題があります：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;olist arabic&amp;quot;&amp;gt;
&amp;lt;ol class=&amp;quot;arabic&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;LLMの善意に依存している。&amp;lt;/strong&amp;gt; 十分に大きいモデルで&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ol&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;複雑なバグを解決することは、命令を回避するのに十分大きい 200kトークンのコンテキストに埋もれたセキュリティ&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;olist arabic&amp;quot;&amp;gt;
&amp;lt;ol class=&amp;quot;arabic&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;それは文脈依存であり、構造的ではありません。プロンプトを変えて、LLMを変えて&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ol&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;セッションを変更する — そしてルールが消える。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;olist arabic&amp;quot;&amp;gt;
&amp;lt;ol class=&amp;quot;arabic&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;それはスケールしない。* 新しいファイルタイプごとに、新しいレベルごとに&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ol&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;機密保持には新しい条項が必要です。あなたのプロンプトは 誰も全てを読まない規制テキスト&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;admonitionblock caution&amp;quot;&amp;gt;
&amp;lt;table&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;icon&amp;quot;&amp;gt;
&amp;lt;i class=&amp;quot;fa icon-caution&amp;quot; title=&amp;quot;🔒&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;
&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;システムのセキュリティは、決して、私たちが命令に依存してはならない 忘れたり、回避したり、あるいは読み込まないこともあります。彼女は何かに依存しなければなりません。 明示的に望まない限り越えられない障壁&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/table&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_私の回答44の行列&amp;quot;&amp;gt;私の回答：4×4の行列&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;私がワークスペースで実装したソリューションは、&amp;lt;strong&amp;gt;ゾーン × マトリックス&amp;lt;/strong&amp;gt; LLMへのアクセス権**. 彼女はLLMに慎重であることを求めない。彼女は 構造的に不可能な軽率さ&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div id=&amp;quot;diag-matrix-overview&amp;quot; class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
skinparam backgroundColor #FEFEFE
skinparam defaultTextAlignment center
skinparam wrapWidth 220

title LLMガバナンスマトリックス — ゾーン × アクセス権
package &amp;quot;ワークスペース&amp;quot; {

  rectangle &amp;quot;根
(円 0)
━━━━━━
Brain dump
自由思考
[LLM禁止]&amp;quot; as Z0 #FFB3B3
  rectangle &amp;quot;configuration/
(円 1)
━━━━━━
シークレット, トークン
プライベートインフラ
[禁止 LLM]&amp;quot; as Z1 #FFB3B3
  rectangle &amp;quot;office/
(サークル 2)
━━━━━━
編集データ
記事、構図
[フィルタード Vision]&amp;quot; as Z2 #FFF3B3
  rectangle &amp;quot;foundry/private/
(サークル 3)
━━━━━━
クローズドソースコード
[データセット プライベート]&amp;quot; as Z3 #B3D9FF
  rectangle &amp;quot;foundry/public/
(サークル 3)
━━━━━━
オープンソースコード
Apache 2.0
[フリーアクセス]&amp;quot; as Z4 #B3FFB3

}

Z0 -[hidden]-&amp;amp;gt; Z1
Z1 -[hidden]-&amp;amp;gt; Z2
Z2 -[hidden]-&amp;amp;gt; Z3
Z3 -[hidden]-&amp;amp;gt; Z4

@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_五つのゾーン空間的次元_rgpd&amp;quot;&amp;gt;五つのゾーン（空間的次元 — RGPD）&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;ワークスペースの各ゾーンには、ファイルを置くことができる場所を決定するGDPRレベルがあります。 ルーティングされる：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;table class=&amp;quot;tableblock frame-all grid-all stretch&amp;quot;&amp;gt;
&amp;lt;colgroup&amp;gt;
&amp;lt;col style=&amp;quot;width: 4.1666%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 4.1666%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 4.1666%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 4.1666%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 4.1666%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 4.1666%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 4.1666%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 4.1666%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 4.1666%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 4.1666%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 4.1666%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 4.1666%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 4.1666%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 4.1666%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 4.1666%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 4.1666%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 4.1666%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 4.1666%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 4.1666%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 4.1666%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 4.1666%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 4.1666%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 4.1666%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 4.1682%;&amp;quot;&amp;gt;
&amp;lt;/colgroup&amp;gt;
&amp;lt;tbody&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;�ゾーン&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;RGPDレベル&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;内容&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;公共のRAGアクセス権&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;根&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;0 — 親密&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;ブレインダンプ、LLM との会話&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;禁止&amp;lt;/strong&amp;gt;— 決してインデックスされない&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;code&amp;gt;configuration/&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;1 — 制限された所有者&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;シークレット, トークン, APIキー&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;禁止&amp;lt;/strong&amp;gt;— 決してインデックスされない&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;code&amp;gt;office/&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;2 — 制限された協働&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;編集データ, フレーミング, 研修&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;フィルタリングされた&amp;lt;/strong&amp;gt;視覚のみ&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;code&amp;gt;foundry/private/&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;3 — 条件付きオープン&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;クローズドソースのコード、非公開のSaaS&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;禁止&amp;lt;/strong&amp;gt;— 専用のプライベートデータセット&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;code&amp;gt;foundry/public/&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;4 — ネイティブなオーディエンス&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;Apache 2.0コード、公開されたプラグイン&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;自由&amp;lt;/strong&amp;gt;— 完全インデックス&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/tbody&amp;gt;
&amp;lt;/table&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;ルールはシンプルです : &amp;lt;strong&amp;gt;ファイルのパスがLLMがそれにできることを決定します。&amp;lt;/strong&amp;gt; メタデータを維持する必要はなく、フロントマターにタグを追加する必要もありません, 各コミットで手動分類は行われません。ファイルは`OSS/&amp;lt;code&amp;gt;? それは公開されています。それは中に`configuration/&amp;lt;/code&amp;gt;? それは触れられない。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_認識論的分類第二次元&amp;quot;&amp;gt;認識論的分類（第二次元）&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;空間的次元は*どこ*へルートするかを示す。しかし、もう一つの軸があり、それが垂直である： &amp;lt;strong&amp;gt;&amp;lt;code&amp;gt;quoi&amp;lt;/code&amp;gt;&amp;lt;/strong&amp;gt; ルータ。認可されたゾーン内の一部のファイルには情報が含まれています そのまま薄めてはいけない：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div id=&amp;quot;diag-epistemic-filter&amp;quot; class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
skinparam backgroundColor #FEFEFE
skinparam defaultTextAlignment center
skinparam wrapWidth 240

title ダブルカスケード — 空間フィルター + 認識フィルター
start

:Le LLM rencontre un fichier;

if (Zone physique ?) then (Cercle 0-1)
  :ACCÈS BLOQUÉ\n(secret, brain dump);
  stop
elseif (Zone CSS/)
  :DROIT D&amp;#39;ACCÈS PRIVÉ\n→ dataset fine-tuning;
  :Filtre épistémique\nVision/Opinion;
  if (Classification ?) then (VISION)
    :Dataset privé\n→ entraînement autorisé;
  else (OPINION)
    :CONFINÉ\n→ pas d&amp;#39;entraînement;
  endif
elseif (Zone office/)
  :DROIT D&amp;#39;ACCÈS FILTRÉ\n→ accès conditionnel;
  :Filtre épistémique\nVision/Opinion/Stratégie;
  if (Classification ?) then (VISION)
    :DILUTION COMPLÈTE\n→ docs racine + blog;
  elseif (STRATÉGIE)
    :DILUTION RESTREINTE\n→ docs racine seulement;
  else (OPINION)
    :CONFINEMENT\n→ office/ uniquement;
  endif
else (Zone OSS/)
  :ACCÈS LIBRE\n→ indexation complète;
endif

stop

@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;エピステミックな分類グリッド、私の統治の規則2bisに刻まれた エージェント :&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;| ステータス | 定義 | LLM シグナル | 宛先 | | VISION | 安定したアーキテクチャ、テスト済みのパターン | 宣言型言語、セッション/テスト参照 | 完全希釈 + ブログ | | 戦略 | ビジネスポジショニング、価格設定 | 市場用語、競争 | ルートドキュメントのみ | | OPINION | 推測、未検証の仮説 | 仮説的な言語、直感 | 隔離 円0 |&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;2つの次元 — 物理的領域 × 認識論的分類 — の組み合わせ 形作る&amp;lt;strong&amp;gt;完全なマトリックス&amp;lt;/strong&amp;gt;:&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div id=&amp;quot;diag-full-matrix&amp;quot; class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
skinparam backgroundColor #FEFEFE

title 完全なマトリックス — ゾーン × 分類
salt
{
{T
+ Zone | VISION | STRATÉGIE | OPINION
+ Racine (0) | ✗ Interdit | ✗ Interdit | ✗ Interdit
+ configuration/ (1) | ✗ Interdit | ✗ Interdit | ✗ Interdit
+ office/ (2) | ✓ Docs + Blog | ✓ Docs seulement | ✗ Confiné
+ CSS/ (3) | ✓ Dataset privé | ✓ Dataset privé | ✗ Confiné
+ OSS/ (4) | ✓ Public libre | ✓ Public libre | ✓ Public libre
}
}

@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_llmはこの行列をどのように消費するか&amp;quot;&amp;gt;LLMはこの行列をどのように消費するか&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;マトリックスはLLMが読むドキュメントではありません。これは&amp;lt;strong&amp;gt;制約 &amp;lt;/strong&amp;gt;暗黙的に** エンコードされた コンテキストの 複合ベクトル (EPIC 9 — 進行中 実装).&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;LLMが各セッションで受け取るもの：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-none hljs&amp;quot;&amp;gt;VECTEUR COMPOSITE DE CONTEXTE
├── RAG pgvector → OSS/ + office/Vision
│   (similarité sémantique sur contenu publiable)
├── Knowledge Graph graphify → OSS/
│   (relations exactes entre artéfacts publics)
├── Knowledge Graph privé → CSS/
│   (relations entre code closed source — jamais exporté)
├── Métadonnées de zone → chaque fichier taggé par zone physique
│   (le LLM sait s&amp;#39;il est dans office/ ou OSS/)
└── Historique des décisions → WORKSPACE_VISION.adoc
    (contexte temporel des arbitrages)&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;具体的には、LLMが私にこう言うとき：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-text hljs&amp;quot; data-lang=&amp;quot;text&amp;quot;&amp;gt;Je vais indexer le contenu de edster/ pour enrichir le knowledge graph...&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;ゾーンメタデータは、LLM が文を終える前に応答する : &amp;lt;code&amp;gt;edster/`である`CSS/&amp;lt;/code&amp;gt;, レベル 3 →&amp;lt;strong&amp;gt;パブリックな knowledge graph へのアクセスは禁止されています。&amp;lt;/strong&amp;gt; RAGはそれを見つけません。グラフはそれに触れません。ユーザーの回答は それを引用していません。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;admonitionblock tip&amp;quot;&amp;gt;
&amp;lt;table&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;icon&amp;quot;&amp;gt;
&amp;lt;i class=&amp;quot;fa icon-tip&amp;quot; title=&amp;quot;💡&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;
&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;空間オントロジーは～のように機能する&amp;lt;strong&amp;gt;Unixのパーミッション&amp;lt;/strong&amp;gt;LLM用の。 プロセスに慎重であるように求めません`/etc/shadow`— その人に読み取りアクセスを拒否します。同じ原則です。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/table&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_実装_型付き_gradle_タスク&amp;quot;&amp;gt;実装 : 型付き Gradle タスク&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;行列は哲学ではない。これはコードです。タスクの契約はこちらです。 Gradle がそれを実装 :&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-kotlin hljs&amp;quot; data-lang=&amp;quot;kotlin&amp;quot;&amp;gt;abstract class ZoneAwareIndexer @Inject constructor(
    private val rootDir: DirectoryProperty,
    private val configServer: ConfigServerProperty  // → configuration/
) : DefaultTask() {

    @Input
    val zoneFilter: SetProperty&amp;amp;lt;Zone&amp;amp;gt; = project.objects.setProperty(Zone::class.java)

    @OutputFile
    val ragIndex: RegularFileProperty = project.objects.fileProperty()

    @TaskAction
    fun index() {
        val allowedPaths = zoneFilter.get().flatMap { it.resolve(rootDir.get()) }
        val forbiddenPaths = Zone.RESTRICTED.resolve(rootDir.get())
                            + Zone.INTIMATE.resolve(rootDir.get())
        // Le RAG ne voit jamais configuration/ ni la racine
        // CSS/ alimente un index privé, pas celui-ci
        // office/ est filtré par le classifieur Vision/Opinion
    }
}

enum class Zone {
    INTIMATE,      // Cercle 0 — racine
    RESTRICTED,    // Cercle 1 — configuration/
    EDITORIAL,     // Cercle 2 — office/
    CLOSED_SOURCE, // Cercle 3 — foundry/private/
    OPEN_SOURCE    // Cercle 3 — foundry/public/
}&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;タスクは &amp;lt;strong&amp;gt;テスト可能&amp;lt;/strong&amp;gt;。あなたは、確認するテストを書くことができます:&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-kotlin hljs&amp;quot; data-lang=&amp;quot;kotlin&amp;quot;&amp;gt;@Test
fun `le RAG n&amp;#39;indexe jamais configuration`() {
    val index = ZoneAwareIndexer(rootDir, configServer)
    index.zoneFilter.set(setOf(Zone.OPEN_SOURCE, Zone.EDITORIAL))
    index.index()

    assertThat(index.ragIndex).doesNotContain(&amp;quot;configuration/&amp;quot;)
}

@Test
fun `le code closed source est exclu du RAG public`() {
    val index = ZoneAwareIndexer(rootDir, configServer)
    index.zoneFilter.set(setOf(Zone.OPEN_SOURCE))  // OSS only

    assertThat(index.ragIndex).doesNotContain(&amp;quot;edster&amp;quot;)
}&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;380 tests, 380 PASS. plantuml-gradleと同様に、セキュリティはテストされています 期待されていなかった。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_なぜこれがマニフェストで単なるスペックではないのか&amp;quot;&amp;gt;なぜこれがマニフェストで、単なるスペックではないのか&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;このドキュメントはアーキテクチャ仕様であり、それが定義するためです：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;いくつかの&amp;lt;strong&amp;gt;サイズ&amp;lt;/strong&amp;gt;(空間的, 認識的)&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;いくつかの&amp;lt;strong&amp;gt;決定論的なルール&amp;lt;/strong&amp;gt;(ゾーン → アクセス権)&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;Un &amp;lt;strong&amp;gt;タスク契約&amp;lt;/strong&amp;gt;(型付きGradle、テスト可能)&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;一つ&amp;lt;strong&amp;gt;参照実装&amp;lt;/strong&amp;gt;( 私のワークスペース )&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;でもそれはまた一つ&amp;lt;strong&amp;gt;マニフェスト&amp;lt;/strong&amp;gt;なぜなら彼は議論に立場を取るから より大きい : &amp;lt;strong&amp;gt;LLMのデータへのアクセスをどのように管理するか？&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;業界の答えは、プロンプトエンジニアリング + ガードレールです&amp;lt;br&amp;gt;
ポストホックな分類器。私の回答は：&amp;lt;strong&amp;gt;ファイルを整理する&amp;lt;/strong&amp;gt; 良いフォルダー。** 残りは自動的です。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;admonitionblock important&amp;quot;&amp;gt;
&amp;lt;table&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;icon&amp;quot;&amp;gt;
&amp;lt;i class=&amp;quot;fa icon-important&amp;quot; title=&amp;quot;❗&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;
&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;このマニフェストは「LLMは整合されるべきだ」とは言わない。それは「整合」と言う。 LLM が あなたの セキュリティ ルール に 対する こと は 、 あなた の システム の 結果 で あ る ファイル、あなたのプロンプトではありません。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/table&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_完全なカスケード_ブレインダンプからブログ記事へ&amp;quot;&amp;gt;完全なカスケード — ブレインダンプからブログ記事へ&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;フルサイクルを示すために、このマトリックスのアイデアがどのように生まれたかをご紹介します そして希釈された：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-none hljs&amp;quot;&amp;gt;Session 4 mai 2026 — Feedback global du workspace
  │
  ├→ Le LLM identifie : &amp;quot;la dualité public/privé est invisible&amp;quot;
  │   → Classifié VISION (constat architectural vérifiable)
  │
  ├→ PICTURE_ME_ROLLIN_MATRICE_4X4.adoc — STIMULUS (Cercle 0)
  │   → Brain dump structuré, classification VISION confirmée
  │
  ├→ DILUTION → WORKSPACE_AS_PRODUCT.adoc (section Matrice 4×4)
  │   → La spec vit dans les documents racine
  │
  ├→ DILUTION → WORKSPACE_ORGANIZATION.adoc (OSS/CSS)
  │   → La granularisation est documentée
  │
  └→ ARTICLE 0117 (ce document) → cheroliv.com
      → La VISION est publiée&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;これはセッション中の観察として始まった (&amp;quot;hé, le RAG ne sait pas 「edster がクローズドソースである」ということがアーキテクチャの仕様になった。 1セッション未満で公開されました。これが STIMULUS パターンが動いている様子です。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_賛成反対&amp;quot;&amp;gt;�賛成/反対&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;table class=&amp;quot;tableblock frame-all grid-all stretch&amp;quot;&amp;gt;
&amp;lt;colgroup&amp;gt;
&amp;lt;col style=&amp;quot;width: 50%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 50%;&amp;quot;&amp;gt;
&amp;lt;/colgroup&amp;gt;
&amp;lt;thead&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;th class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;このアプローチ (空間オントロジー + マトリクス)&amp;lt;/th&amp;gt;
&amp;lt;th class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;クラシックアプローチ（プロンプト＋ガードレール）&amp;lt;/th&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/thead&amp;gt;
&amp;lt;tbody&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;メカニクス&amp;lt;/strong&amp;gt; — ファイルシステムがアクセスをブロックし、LLMではありません&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;Déclarative&amp;lt;/strong&amp;gt; — プロンプトは LLM に慎重であるよう求める&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;Testable&amp;lt;/strong&amp;gt; — Gradleタスクの契約は380+テストで検証されています&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;テスト不能&amp;lt;/strong&amp;gt; — &amp;quot;LLMはルールを守ったか？&amp;quot; はオープンな質問です&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;LLMに依存しない&amp;lt;/strong&amp;gt; — モデルを変更し、フォルダはそのまま&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;LLMに依存している&amp;lt;/strong&amp;gt; — 各モデルはプロンプトを異なるように解釈する&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;スケーラブル&amp;lt;/strong&amp;gt; — 新しいデータ型 = 新しいフォルダー, コード変更なし&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;非スケーラブル&amp;lt;/strong&amp;gt; — 新しいデータ型 = 新しいプロンプト句, 新しい回帰リスク&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;監査可能&amp;lt;/strong&amp;gt; — ファイルシステムは監査証跡です&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;監査不能&amp;lt;/strong&amp;gt; — プロンプトには履歴がなく、差分もなく、責任もない&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;Contrainte&amp;lt;/strong&amp;gt; : 初期の組織的な規律が必要です&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;Contrainte&amp;lt;/strong&amp;gt; : プロンプトの作成における規律を毎回のセッションで求める&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/tbody&amp;gt;
&amp;lt;/table&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_結論_ファイルを整理しプロンプトは整理しない&amp;quot;&amp;gt;結論 : ファイルを整理し、プロンプトは整理しない&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;私が説明したLLMガバナンスマトリックスは製品ではありません。 これは&amp;lt;strong&amp;gt;アーキテクチャ仕様&amp;lt;/strong&amp;gt;— そしてそれが理由で彼女は 公開可能な。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;それを頑健にしているのは、LLMに何も求めないからです。彼女は 彼に 信じない。彼女は自分の整合性と理解に頼っていない。 フランス語、あるいはその善意。ファイルシステムに基づいています — 最も低く、最も安定し、最もテストされた、スタック全体の層。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;私が私のLLMに「全部インデックスできる」と言うとき`OSS/&amp;lt;code&amp;gt;, 何も `configuration/&amp;lt;/code&amp;gt;, et &amp;lt;code&amp;gt;office/&amp;lt;/code&amp;gt;「ビジョン」と分類されている場合のみ&amp;quot; — これは指示ではありません。これは*フィルター*— Kotlinで実装されています 380のテストで検証済み、LLMがデータを見る前に実行。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;これは、誰かに「この引き出しを見ないで」と言うことの違いです。 そして、鍵付き引き出しを閉じる。私が構築してきたエージェントガバナンスは 数か月が鍵です。マトリックスは家具の設計図です。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_参照&amp;quot;&amp;gt;参照&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;0116_compartimentage_epistemique_automatise_llm_post.html&amp;quot;&amp;gt;Article 0116 — 自動化された認識論的区画&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;0114_gouvernance_cercles_confiance_ontologie_spatiale_alignement_llm_post.html&amp;quot;&amp;gt;Article 0114 — 信頼の円と空間オントロジー&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;0108_gouvernance_agent_opencode_eager_lazy_post.html&amp;quot;&amp;gt;Article 0108 — AsciiDocでAIエージェントを管理する&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;../2026/0115_anonymiseur_dataset_mvp0_realite_augmentee_llm_post.html&amp;quot;&amp;gt;記事 0115 — 匿名化ツール MVP0&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;</description>
        </item><item>
            <title>OSS/CSSの細分化 — なぜ私は foundry/ を二つに分けたのか</title>
            <link >https://cheroliv.com/blog/2026/0117_granularisation_oss_css_repositorie_workspace_post.html</link>
            <pubDate>Sun, 3 May 2026 00:00:00 +0000</pubDate>
            <guid isPermaLink="false">blog/2026/0117_granularisation_oss_css_repositorie_workspace_post.html</guid>
            <description>&amp;lt;div id=&amp;quot;toc&amp;quot; class=&amp;quot;toc&amp;quot;&amp;gt;
&amp;lt;div id=&amp;quot;toctitle&amp;quot;&amp;gt;Table des matières&amp;lt;/div&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel1&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_起きるべくして起きた事故&amp;quot;&amp;gt;起きるべくして起きた事故&amp;lt;/a&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel2&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_真の質問&amp;quot;&amp;gt;真の質問&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_ソリューション_ossおよび_css&amp;quot;&amp;gt;ソリューション : OSS/および CSS/&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_なぜ_oss_と_css_でpublic_と_private_でないのか&amp;quot;&amp;gt;なぜ &amp;quot;OSS&amp;quot; と &amp;quot;CSS&amp;quot; で、&amp;quot;Public&amp;quot; と &amp;quot;Private&amp;quot; でないのか。&amp;lt;/a&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel2&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_完全な木_四つのゾーン三つではない&amp;quot;&amp;gt;完全な木 — 四つのゾーン、三つではない&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_特別なケースcheroliv_com&amp;quot;&amp;gt;特別なケース：cheroliv.com&amp;lt;/a&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel2&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_構わない&amp;quot;&amp;gt;構わない&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_ガバナンスエージェントへの影響&amp;quot;&amp;gt;ガバナンスエージェントへの影響&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_私たちが得るもの_そして失うもの&amp;quot;&amp;gt;私たちが得るもの （そして失うもの）&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_結論_物理信号はソフトウェア信号に勝る&amp;quot;&amp;gt;結論 : 物理信号はソフトウェア信号に勝る&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_参照&amp;quot;&amp;gt;参照&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div id=&amp;quot;preamble&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;読了時間 : 10 minutes&amp;lt;/div&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;code&amp;gt;foundry/&amp;lt;/code&amp;gt;— 私のワークスペースのコードをホストする機能領域 — 18のプロジェクトが含まれています。 8つはApache 2.0ライセンスのオープンソースです。 ただ1つだけは closed source — SaaS Edster。数か月間、これらの9つのプロジェクトは共存していた 同じフォルダー内にあり、&amp;amp;#8230;&amp;amp;#8203; 以外に何も区切られていない。それらの公開/非公開ステータス それは私の頭の中の情報で、ファイルシステムにはありませんでした。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;それから、RAGを接続したくなった。そこで、すべてが崩れた。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_起きるべくして起きた事故&amp;quot;&amp;gt;起きるべくして起きた事故&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;2026年4月、slider-gradle用のpgvector RAGの実装を開始しました。 原則：すべてのリポジトリをインデックス化する`foundry/&amp;lt;code&amp;gt;,生産する embeddings, そしてそれらをLLMのコンテキストに注入して、それを持たせるために ファイルの&amp;quot;認識`foundry/&amp;lt;/code&amp;gt;。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;パイプラインはシンプルでした：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-kotlin hljs&amp;quot; data-lang=&amp;quot;kotlin&amp;quot;&amp;gt;val repos = fileTree(rootDir) {
    include(&amp;quot;**/*.adoc&amp;quot;, &amp;quot;**/*.kts&amp;quot;, &amp;quot;**/*.kt&amp;quot;, &amp;quot;**/*.json&amp;quot;, &amp;quot;**/*.yml&amp;quot;)
}
val chunks = repos.map { chunk(it) }
val embeddings = chunks.map { embed(it) }
pgvector.insert(embeddings)&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;シンプル。効果的。そして&amp;lt;strong&amp;gt;危険な&amp;lt;/strong&amp;gt;。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;なぜならこれ`fileTree`区別しない`plantuml-gradle/` (Apache 2.0, public) と`edster/`(closed source, private). 全部飲み込む。 もし私がいつかこれらの埋め込みを公開したら — ダッシュボード上、または回答の中に LLM、トレーニングデータセット — Edsterの独自コードが漏洩しています。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;admonitionblock caution&amp;quot;&amp;gt;
&amp;lt;table&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;icon&amp;quot;&amp;gt;
&amp;lt;i class=&amp;quot;fa icon-caution&amp;quot; title=&amp;quot;🔒&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;
&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;問題は、LLMがクローズドソースのコードを読むことではない。問題は、 それは、このコードが公開ベクトル埋め込みに終わること — 不可逆、削除不能、監査不能&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/table&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_真の質問&amp;quot;&amp;gt;真の質問&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;それは「LLMがコードを漏らさないようにするにはどうすればいいですか？」ではない。それは「どうやって」だ 逃げを構造的に不可能にする？&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;答えはプロンプトではありません。答えは、フォルダーを二つに分けることです。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_ソリューション_ossおよび_css&amp;quot;&amp;gt;ソリューション : OSS/および CSS/&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;前：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-none hljs&amp;quot;&amp;gt;foundry/
├── plantuml-gradle/       ← public
├── bakery-gradle/         ← public
├── magic-stick/           ← public
├── edster/                ← PRIVÉ
├── slider-gradle/         ← public
└── ...                    ← mélange invisible&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;後：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-none hljs&amp;quot;&amp;gt;foundry/
├── OSS/                   ← tout est Apache 2.0
│   ├── plantuml-gradle/
│   ├── bakery-gradle/
│   ├── magic-stick/
│   ├── slider-gradle/
│   └── ...
└── CSS/                   ← tout est closed source / private
    └── edster/&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;Le `fileTree`になります :&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-kotlin hljs&amp;quot; data-lang=&amp;quot;kotlin&amp;quot;&amp;gt;val ossRepos = fileTree(File(rootDir, &amp;quot;OSS&amp;quot;)) {
    include(&amp;quot;**/*.adoc&amp;quot;, &amp;quot;**/*.kts&amp;quot;, &amp;quot;**/*.kt&amp;quot;, &amp;quot;**/*.json&amp;quot;, &amp;quot;**/*.yml&amp;quot;)
}
val cssRepos = fileTree(File(rootDir, &amp;quot;CSS&amp;quot;)) {
    include(&amp;quot;**/*.adoc&amp;quot;, &amp;quot;**/*.kts&amp;quot;, &amp;quot;**/*.kt&amp;quot;, &amp;quot;**/*.json&amp;quot;, &amp;quot;**/*.yml&amp;quot;)
}

// Embeddings publics — OSS seulement
pgvectorPublic.insert(ossRepos.map { chunk(it) }.map { embed(it) })

// Dataset fine-tuning privé — CSS seulement
fineTuningDataset.insert(cssRepos.map { chunk(it) })  // jamais publié&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;admonitionblock important&amp;quot;&amp;gt;
&amp;lt;table&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;icon&amp;quot;&amp;gt;
&amp;lt;i class=&amp;quot;fa icon-important&amp;quot; title=&amp;quot;❗&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;
&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;公共のRAGは決して見ない`CSS/`. クローズドソースのコードはデータセットを供給する ファインチューニングされていない — 私の家から決して出ない内部モデル。La 分離は機械的で、宣言的ではない。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/table&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_なぜ_oss_と_css_でpublic_と_private_でないのか&amp;quot;&amp;gt;なぜ &amp;quot;OSS&amp;quot; と &amp;quot;CSS&amp;quot; で、&amp;quot;Public&amp;quot; と &amp;quot;Private&amp;quot; でないのか。&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;OSS（オープンソースソフトウェア）およびCSS（クローズドソースソフトウェア）の略称の選択 熟慮された：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;Public&amp;quot;/&amp;quot;Private&amp;quot; 説明します&amp;lt;strong&amp;gt;視認性&amp;lt;/strong&amp;gt;(GitHubが見ているもの)&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;OSS&amp;quot;/&amp;quot;CSS&amp;quot;は&amp;amp;#8230;&amp;amp;#8203;を説明する&amp;lt;strong&amp;gt;自然&amp;lt;/strong&amp;gt;コード (LLMが知っておくべきこと)&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;GitHubの可視性はリモートリポジトリのメタデータです。 コードの性質は コンテンツのプロパティです。LLM は GitHub API へのアクセスがありませんが、アクセスがあります。 ファイルシステムに。&amp;lt;code&amp;gt;CSS/&amp;lt;/code&amp;gt;「注意、このコードはライセンスで保護されていません。」 libre&amp;quot; 読む必要なく`LICENSE`またはパースする`package.json`.&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;admonitionblock tip&amp;quot;&amp;gt;
&amp;lt;table&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;icon&amp;quot;&amp;gt;
&amp;lt;i class=&amp;quot;fa icon-tip&amp;quot; title=&amp;quot;💡&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;
&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;フォルダーの名前は、あなたが与えることができる最も堅牢なメタデータに LLM. 彼女は誤ってパースされたり、無視されたり、誤って解釈されたりすることはできません。このLLM 見る`CSS/edster/`ファイルのパスの中 — 彼は知っている。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/table&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_完全な木_四つのゾーン三つではない&amp;quot;&amp;gt;完全な木 — 四つのゾーン、三つではない&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;OSS/CSSの細分化は3領域オントロジーを完成させます。領域 `foundry/`機能的サブゾーンが1から2に変更されます :&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div id=&amp;quot;diag-four-zone-workspace&amp;quot; class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
skinparam backgroundColor #FEFEFE
skinparam defaultTextAlignment center
skinparam wrapWidth 260

title ファウンドリー/ — OSS/CSSの細粒化
package &amp;quot;鋳造所/&amp;quot; {

  package &amp;quot;円0 — 根&amp;quot; #FFCCCC {
    rectangle &amp;quot;PICTURE_ME_ROLLIN_*.adoc&amp;quot; as STIM
    rectangle &amp;quot;WORKSPACE_*.adoc&amp;quot; as VISION_DOC
    note right of STIM
      Brain dump libre
      Jamais versionné
      [LLM : interdit d&amp;#39;indexer]
    end note
  }

  package &amp;quot;サークル 1 — 設定/&amp;quot; #FFD9CC {
    rectangle &amp;quot;秘密, トークン&amp;quot; as SECRETS
    rectangle &amp;quot;Spring Cloud Config&amp;quot; as SCC
    note right of SECRETS
      Privé-CVS, solo access
      [LLM : INTERDIT]
    end note
  }

  package &amp;quot;サークル 2 — オフィス/&amp;quot; #FFFFCC {
    rectangle &amp;quot;記事, フレーミング&amp;quot; as DATA
    rectangle &amp;quot;研修, SPG/SPD&amp;quot; as FORM
    note right of DATA
      Privé-CVS
      [LLM : filtré Vision/Opinion]
    end note
  }

  package &amp;quot;円 3 — foundry/&amp;quot; #CCE5FF {
    package &amp;quot;OSS/ — Apache 2.0&amp;quot; #CCFFCC {
      rectangle &amp;quot;Gradle プラグイン&amp;quot; as PLUGINS
      rectangle &amp;quot;エンジン&amp;quot; as ENGINE
    }
    package &amp;quot;CSS/ — クローズドソース&amp;quot; #CCDDFF {
      rectangle &amp;quot;edster/&amp;quot; as EDSTER
    }
  }
}

@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;| ゾーン | GDPR | パブリック RAG インデックス | データセット ファインチューニング | | ルート | レベル0 — 親密 | ✗ | ✗ | | &amp;lt;code&amp;gt;configuration/&amp;lt;/code&amp;gt;| レベル 1 — 制限 | ✗ | ✗ | | &amp;lt;code&amp;gt;office/&amp;lt;/code&amp;gt;| レベル 2 — コラボラティブ | ✓ フィルタ済み | ✓ フィルタ済み | | &amp;lt;code&amp;gt;foundry/private/&amp;lt;/code&amp;gt;| レベル 3 — 条件付きオープン | ✗ | ✓ プライベート | | &amp;lt;code&amp;gt;foundry/public/&amp;lt;/code&amp;gt;| レベル 4 — ネイティブ公開 | ✓ 無料 | ✓ 公開 |&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_特別なケースcheroliv_com&amp;quot;&amp;gt;特別なケース：cheroliv.com&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;私がそこにいた間に、別の矛盾も修正しました。私のサイト &amp;lt;code&amp;gt;cheroliv.com`に住んでいた`foundry/`ソフトウェアプロジェクトのように スタンドアロン — 独自のGradleビルド、独自のCI、独自の ガバナンス&amp;lt;/code&amp;gt;.agents/`。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;しかし、ブログ記事はコードではありません。これらは&amp;lt;strong&amp;gt;データ 社説&amp;lt;/strong&amp;gt; Cercle 2 — フレーミングと同様に`office/pilotage/` または形成の`office/formations/`.&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-none hljs&amp;quot;&amp;gt;AVANT                            APRÈS
foundry/                office/
  cheroliv.com/                    sites/
    site/jbake/content/blog/         cheroliv.com/
      2026/0117_....adoc               2026/0117_....adoc&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;変更点:&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;記事は`office/`→ Cercle 2のプライバシー&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;タスク`publishSite`になる能力の`engine`&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;経由`bakery-gradle`— プラグインは一つ受け取ります`FileTree`, 彼は知らない 記事がどこから来るか`office/`&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;単一のCI、単一のガバナンス — 重複ゼロ&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;ビジョン/オピニオン・クラスファイア（規則2ビス）自動的に適用されます：&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;記事の中の`office/`公開前にフィルタリングされます&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_構わない&amp;quot;&amp;gt;構わない&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;それが美しい。プラグイン`bakery-gradle`変更されていません。 AsciiDocコンテンツのディレクトリを受け取り、HTMLを生成し、プッシュする GitHub Pagesで。このディレクトリは`site/jbake/content/` ou &amp;lt;code&amp;gt;office/sites/cheroliv/&amp;lt;/code&amp;gt;— プラグインは気にしない。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-kotlin hljs&amp;quot; data-lang=&amp;quot;kotlin&amp;quot;&amp;gt;// engine/build.gradle.kts
task(&amp;quot;publishBlog&amp;quot;) {
    doLast {
        val articles = fileTree(&amp;quot;../../office/sites/cheroliv/2026/&amp;quot;)
        bakery.generate(articles)  // ← bakery ne sait pas d&amp;#39;où ça vient
    }
}&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;インターフェイス契約は Gradle のタスクです。REST API ではありません。ウェブフックではありません。 タスク — タイプ指定され、テスト可能、ローカルおよび CI で実行可能。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_ガバナンスエージェントへの影響&amp;quot;&amp;gt;ガバナンスエージェントへの影響&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;OSS/CSSの細粒度化は、エージェントガバナンスを3つのポイントで変更します：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;olist arabic&amp;quot;&amp;gt;
&amp;lt;ol class=&amp;quot;arabic&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;RAG public&amp;lt;/strong&amp;gt; : インデックス範囲は`foundry/**`&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ol&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;à &amp;lt;code&amp;gt;foundry/public/&amp;lt;strong&amp;gt;&amp;lt;/code&amp;gt;+&amp;lt;code&amp;gt;office/Vision/&amp;lt;/strong&amp;gt;&amp;lt;/code&amp;gt;. クローズドソースのコード タスクの設定によってインデックスから除外されます。プロンプトによってではありません。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;olist arabic&amp;quot;&amp;gt;
&amp;lt;ol class=&amp;quot;arabic&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;知識グラフ&amp;lt;/strong&amp;gt; : graphify-gradle は2つのグラフを生成します :&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ol&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;*&amp;lt;code&amp;gt;office/graph.json&amp;lt;/code&amp;gt;(公開) — OSSアーティファクトとoffice/Visionの関係 *&amp;lt;code&amp;gt;configuration/graph_private.json&amp;lt;/code&amp;gt;(gitignored, privé) — の間の関係 CSSのアーティファクト、未公開&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;olist arabic&amp;quot;&amp;gt;
&amp;lt;ol class=&amp;quot;arabic&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;データセットファインチューニング&amp;lt;/strong&amp;gt; :`codebase-gradle`現在は2つのソースがあります：&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ol&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;*&amp;lt;code&amp;gt;OSS/&amp;lt;/code&amp;gt;→ パブリックデータセット (コミュニティモデル、ベンチマーク) *&amp;lt;code&amp;gt;CSS/&amp;lt;/code&amp;gt;→ プライベートデータセット (内部モデル, 独自のファインチューニング)&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_私たちが得るもの_そして失うもの&amp;quot;&amp;gt;私たちが得るもの （そして失うもの）&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;table class=&amp;quot;tableblock frame-all grid-all stretch&amp;quot;&amp;gt;
&amp;lt;colgroup&amp;gt;
&amp;lt;col style=&amp;quot;width: 7.1428%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 7.1428%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 7.1428%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 7.1428%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 7.1428%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 7.1428%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 7.1428%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 7.1428%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 7.1428%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 7.1428%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 7.1428%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 7.1428%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 7.1428%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 7.1436%;&amp;quot;&amp;gt;
&amp;lt;/colgroup&amp;gt;
&amp;lt;tbody&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;前 (フラットフォルダー)&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;(OSS/CSS + office/sites) 後&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;code&amp;gt;ls foundry/&amp;lt;/code&amp;gt;→ 公私混合&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;code&amp;gt;ls foundry/public/&amp;lt;/code&amp;gt;→ すべて公開可能&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;RAGは差別なくすべてをインデックスする&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;RAGはインデックスを作成します`OSS/`+`office/Vision`専ら&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;プロジェクトがオープンソースかどうか分からない&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;道`OSS/` ou `CSS/`いわゆる&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;cheroliv.com は独自の CI と独自のガバナンスを持っています&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;CI とガバナンスは engine で共有されています&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;ブログの記事は「code」リポジトリにあります。&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;ブログ記事は`office/sites/`— データ、コードではない&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;クローズドソースコードがパブリックな埋め込みに漏洩するリスク&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;構造的に不可能 —`CSS/`RAG のスコープ外&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/tbody&amp;gt;
&amp;lt;/table&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;唯一のコスト：一つ`git mv`17のOSSリポジトリに対するグローバル + のリファクター &amp;lt;code&amp;gt;build.gradle.kts&amp;lt;/code&amp;gt; de &amp;lt;code&amp;gt;engine&amp;lt;/code&amp;gt;. これはコールドマイグレーションです — データは飛行中に存在せず、影響を受けたユーザーもいません。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_結論_物理信号はソフトウェア信号に勝る&amp;quot;&amp;gt;結論 : 物理信号はソフトウェア信号に勝る&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;私がこの午後にしたことは、見えない慣習を置き換えること そのエリア内の目に見える分離によって`foundry/&amp;lt;code&amp;gt;. 以前、あなたは～なければならなかった 知っているが`edster/`クローズドソースでした。 今、あなたはそれを*見る* — フォルダーは呼ばれる`CSS/&amp;lt;/code&amp;gt;。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;これはUnixのパーミッション、ネットワークのVLAN、またはの同じ原理です データベース内の防火区画。セキュリティは 覚えておくべき情報でなければならず、それはプロパティでなければなりません。 &amp;lt;strong&amp;gt;物理&amp;lt;/strong&amp;gt;システムの。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;OSS/CSSの細分化は、この原理をその分野に適用したものです。 LLMのガバナンスについて。 LLMはEdsterが何であるかを知る必要はありません 機密です。 彼はそれをインデックス付けできない状態である必要があります。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;それがまさにそれ`CSS/`保証する。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_参照&amp;quot;&amp;gt;参照&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;0118_matrice_gouvernance_llm_zone_acces_workspace_post.html&amp;quot;&amp;gt;条項0117 — LLMガバナンスマトリックス&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;0114_gouvernance_cercles_confiance_ontologie_spatiale_alignement_llm_post.html&amp;quot;&amp;gt;記事 0114 — 信頼のサークル&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;0116_compartimentage_epistemique_automatise_llm_post.html&amp;quot;&amp;gt;Article 0116 — 自動化された認識論的区画化&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;0108_gouvernance_agent_opencode_eager_lazy_post.html&amp;quot;&amp;gt;記事 0108 — AsciiDocを使用したAIエージェントの管理&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;</description>
        </item><item>
            <title>自動化された認識の区画化 — LLMが私のメンタルガーデンをどのように守るか</title>
            <link >https://cheroliv.com/blog/2026/0116_compartimentage_epistemique_automatise_llm_post.html</link>
            <pubDate>Sat, 2 May 2026 00:00:00 +0000</pubDate>
            <guid isPermaLink="false">blog/2026/0116_compartimentage_epistemique_automatise_llm_post.html</guid>
            <description>&amp;lt;div id=&amp;quot;toc&amp;quot; class=&amp;quot;toc&amp;quot;&amp;gt;
&amp;lt;div id=&amp;quot;toctitle&amp;quot;&amp;gt;Table des matières&amp;lt;/div&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel1&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_問題何も発表せずに自由に考える&amp;quot;&amp;gt;問題：何も発表せずに自由に考える&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_stimulus_パターン_生まれる固定する薄める死ぬ&amp;quot;&amp;gt;STIMULUS パターン — 生まれる、固定する、薄める、死ぬ&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_llmへの委任_なぜllmがフィルタリングするのか&amp;quot;&amp;gt;LLMへの委任 : なぜLLMがフィルタリングするのか&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div id=&amp;quot;preamble&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;読了時間 : 10 minutes&amp;lt;/div&amp;gt;
&amp;lt;p&amp;gt;私のLLMはGradleタスクを実行するだけにとどまらない。それは私のプライベートな思考と公的な表現の間の境界の守護者である。各アイデアはルーティングされる前に、Vision、Opinion、Stratégieと分類される。これがどのようにして自動化された認識的コンパートメンタル化が私の精神的な庭を守り、私を黙らせずにいるかを示す。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;dlist&amp;quot;&amp;gt;
&amp;lt;dl&amp;gt;
&amp;lt;dt class=&amp;quot;hdlist1&amp;quot;&amp;gt;トック&amp;lt;/dt&amp;gt;
&amp;lt;dd&amp;gt;
&amp;lt;p&amp;gt;[]&amp;lt;/p&amp;gt;
&amp;lt;/dd&amp;gt;
&amp;lt;/dl&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_問題何も発表せずに自由に考える&amp;quot;&amp;gt;問題：何も発表せずに自由に考える&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;一人の開発者がLLMを使って思考プロセスをドキュメント化するとき、パラドックスにぶつかる：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-none hljs&amp;quot;&amp;gt;CAPTURE TOUT (Cercle 0, jardin secret)
  ├→ Brain dump libre, pas de censure
  ├→ Idées brutes, spéculations, intuitions non vérifiées
  ├→ Allers-retours LLM : challenger, itérer, raffiner
  └→ Le LLM voit TOUT — le bon, le flou, l&amp;#39;embryonnaire

PUBLICATION SÉLECTIVE (Cercle 4, blog public)
  ├→ Uniquement les décisions actées
  ├→ Uniquement les patterns testés (&amp;amp;gt;100 tests PASS)
  ├→ Uniquement ce qui a de la valeur pour le lecteur
  └→ JAMAIS une spéculation présentée comme une vérité&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;これらの二つの極端の間に、一つ&amp;lt;strong&amp;gt;フィルター&amp;lt;/strong&amp;gt;. 質問は：誰がそれをするのか？疲れた人間（セッションの終わり）？ naïveな正規表現スクリプト？それとも、すでに全部読んでいるLLM自身か？&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;私の回答 : LLM。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_stimulus_パターン_生まれる固定する薄める死ぬ&amp;quot;&amp;gt;STIMULUS パターン — 生まれる、固定する、薄める、死ぬ&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;STIMULUS は ファイル です`.adoc`一時的なワークスペースのルート（Cercle 0）。その名前は印象的な命名規則に従っています —&amp;lt;code&amp;gt;PICTURE_ME_ROLLIN.adoc&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;HOLD_MY_BEER.adoc&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ONCE_UPON_A_TIME.adoc&amp;lt;/code&amp;gt;— その瞬間の探求的意図を捉える。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;そのライフサイクルは容赦がない：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-none hljs&amp;quot;&amp;gt;CRÉATION (Cercle 0)
  ├→ Fichier vide, brain dump libre
  ├→ Allers-retours LLM ← → développeur
  └→ Aucune pression de structure ou de publication

MATURATION
  ├→ Le contenu se densifie
  ├→ Des sections émergent naturellement
  └→ Le fichier devient une référence informelle de session

CLASSIFICATION ÉPISTÉMIQUE ← FAIT PAR LE LLM
  ├→ VISION    → publiable, diluer dans les docs publics + blog
  ├→ OPINION   → confiner au Cercle 0, pas de dilution externe
  └→ STRATÉGIE → dilution restreinte (docs racine, PAS de blog)

DILUTION (Cascade vers Cercles légitimes)
  ├→ VISION → WORKSPACE_AS_PRODUCT.adoc + WHAT_THE_GAMES.adoc + blog
  ├→ STRATÉGIE → WORKSPACE_AS_PRODUCT.adoc (section business)
  └→ OPINION → reste dans le stimulus, ne bouge pas

ARCHIVAGE + SUPPRESSION
  ├→ Snapshot dans configuration/vision-archive/ (trace historique)
  └→ rm du stimulus — il a fini son travail&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;2回以上のセッションで希釈されずに生存する刺激は、アンチパターンです。情報が一時ファイルに保存されるほど重要である場合は（→ diluer）、あるいは情報が不明確で存在する価値がない場合は（→ supprimer）。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_llmへの委任_なぜllmがフィルタリングするのか&amp;quot;&amp;gt;LLMへの委任 : なぜLLMがフィルタリングするのか&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;KotlinでVision/Opinionの分類をハードコードしません。これを注入します&amp;lt;strong&amp;gt;システムプロンプト&amp;lt;/strong&amp;gt;LLMを経由して`AGENT_GOVERNANCE.adoc`:&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-none hljs&amp;quot;&amp;gt;----
----
Pour chaque dilution de stimulus ou session, tu es responsable de classifier
le contenu :
- VISION : décision architecturale actée, pattern testé en production (&amp;amp;gt;100 tests PASS),
  décision documentée dans BACKLOG ou ROADMAP
- OPINION : spéculation, hypothèse non validée par des tests, intuition
  sans ancrage expérimental
- STRATEGIE : positionnement business, pricing, marché cible

Règles :
- Si OPINION, le contenu reste confiné dans son cercle d&amp;#39;origine
- Si VISION, tu procèdes à la dilution dans les documents racine
- Si STRATEGIE, dilution restreinte (docs racine, pas de blog public)
- Cette classification détermine aussi si un article de blog est publiable
  sur cheroliv.com
----

LLMはこの指示を読む**前に**セッションを処理する。それはその直近のコンテキストにあり、別ファイルにはありません。これは *決定的プロンプトエンジニアリング* : 振る舞いは注入されたテキストから生じ、外部の分類器からではありません。

=== なぜそれが機能するのか — そしてなぜそれが直感に反するのか

標準的な反応： 「AIに分類を任せるの？ もし間違えたらどうするの？」

回答 : 人間は午前2時にもっと良くなるわけではない。違いは、LLMはすべてを読むということだ。セッションと対象ドキュメントのコンテキストを完全に把握している。それは`VPS ECO-16 12€ HT`はインフラストラクチャーの決定 (VISION) である一方で`« le TTS ElevenLabs sonne plus naturel que Coqui »`ベンチマークで検証されていない意見です。

人間はセッションの終わりに斜め読みし、できるだけのことをする。LLMは網羅的に読み、体系的なグリッドを適用する。結果は**より信頼できる**、決して少なくない

そして20％の曖昧なケースについては — つまりLLMでも躊躇する灰色の領域 — 答えは「コードを追加すること」ではありません。答えは**LangGraph4j**(EPIC 13) : あいまいなケースでは Human-in-the-Loop ノードを起動し、人間に判断を仰ぐ状態グラフ。ただし、80% の明確なケースでは LLM で十分。

== 完全なパイプ: ブレインダンプからブログ投稿まで

ここに完全なフローがあります — 原始的なアイデアから公開された記事まで — LLMだけがフィルターとして機能しています：

[source]
----
CERCLE 0 (jardin secret)
  PICTURE_ME_ROLLIN.adoc   ← brain dump, allers-retours LLM
       ↓
  [LLM classifie] → VISION / OPINION / STRATÉGIE
       ↓
  VISION → dilution dans WORKSPACE_AS_PRODUCT.adoc
         → dilution dans WHAT_THE_GAMES_BEEN_MISSING.adoc
         → dilution dans WORKSPACE_VISION.adoc (session context)
         → RÉDACTION ARTICLE BLOG ← le LLM écrit, pas le dev
       ↓
CERCLE 4 (blog public)
  0116_compartimentage_epistemique.adoc  ← publié sur cheroliv.com
       ↓
  ./gradlew deploy (bakery-gradle → JBake → JGit → GitHub Pages)
       ↓
  https://cheroliv.com/blog/2026/0116/  ← live
----

開発者は記事を書かない。彼は挑戦し、見直し、検証する。LLMが書く。ループは：

1. ブレインダンプ フリー → 検閲なし
2. LLMによる認識論的分類 → 漏洩なし
3. LLM による執筆 → 先延ばししない
4. 人間による校閲 → エラーなし

歴史的なボトルネック — 「書く時間がない」 — が解消されました。LLMが大半の仕事をこなす。人間がすることは、人間だけができること：判断する。

== 三つのルートドキュメント — 情報がその場所を見つける方法

各ターゲットドキュメントは希釈のカスケードにおいて正確な役割を果たします：

[cols=&amp;quot;1,3,2&amp;quot;]
|===
|ドキュメント |受けるもの |コンテンツの種類 |`WORKSPACE_AS_PRODUCT.adoc` |アーキテクチャ上の意思決定, 技術スタック, ロードマップ, ビジネスモデル |ビジョン＋戦略 |`WHAT_THE_GAMES_BEEN_MISSING.adoc` |パターン、教訓、アンチパターン、オントロジー、形式的ルール |ビジョン (テスト済みのパターン) |`WORKSPACE_VISION.adoc` |セッションコンテキスト, 意思決定の履歴, インフラストラクチャポイント |ビジョン + 戦略 (コンテキスト) |`AGENT_GOVERNANCE.adoc` |ガバナンス規則, プロジェクトポートフォリオ, 手順 |ビジョン(ガバナンス) |**ブログ cheroliv.com** |公開記事、外部読者への価値 |VISIONのみ
|===

同じ刺激は4つのドキュメント + ブログに栄養を与えることができます — 各宛先は自分に関係する部分を受け取り、冗長も矛盾もありません。

それが起きたのは`PICTURE_ME_ROLLIN.adoc`(2026年5月3日):

| 情報 | 分類 | 行き先 | | 13+個のファウンドリープロジェクトの在庫 foundry/ | VISION | WORKSPACE_AS_PRODUCT | | VPS-2 OVH, edster.cloud, 8.49€/月 | VISION | WORKSPACE_AS_PRODUCT + WORKSPACE_VISION |  アフリカ市場はモバイルマネーに備えている » | 戦略 | WORKSPACE_AS_PRODUCT (section business)  DeepSeek &amp;amp;gt; Kimi &amp;amp;gt; GLM 長いコンテキスト用 » | 意見 → ビジョン | 閉じ込められた後、ベンチマーク後に昇進 (記事 0112) | 合成従業員として最終製品 | 戦略 | WORKSPACE_AS_PRODUCT (ブログなし) |

== ベビーステップパターン＋TestContainer＋生きているドキュメント ― 自己テストするコード

STIMULUS/Dilution パターンは思考を管理します。コードにおけるその相当物は、plantuml-gradle によって検証された Baby-Step/TestContainer/Doc Vivante パターンです（380/380 テスト PASS、ドッカーレークがゼロの 137 セッション）：

[cols=&amp;quot;1,3&amp;quot;]
|===
|原理 |ルール |**ベイビーステップ** |USあたり3ポイントを超えてはならない。USが恐ろしいと感じたら、分割する。通過する1ポイントのUS &amp;amp;gt; 遅れる8ポイントのUS。 |**TestContainer まず** |ビジネスコードの前に、コンテナ。 インフラテストがパス → 安定した環境が保証される。 |**コミット済みデータセット** |最小限ながら代表的な部分集合である`src/test/resources/`, PIIなし. クローン可能、起動可能。 |**生きたドキュメンテーション** |各Cucumberテスト = 自然言語の文章。ソースコードが実行可能なスペックである。Markdownドキュメントを維持する必要はゼロ。 |**自動クリーンアップ** |リソース漏れゼロ。 孤児コンテナ,`/tmp/gradle-test-*`: すべてが掃除されました。
|===

このパターンが、plantuml-gradle が 138 セッションで Docker の回帰を一度も経験していない理由です。これは、PostgreSQL、Redis、Kafka などの外部インフラストラクチャと通信するコードが、常に本番と同一の環境でテストされることを保証します — バージョン管理され、再現可能で、1 コマンドで起動できます。

== 結論：出版を恐れずに考える自由

自動化された認識論的な区画化は検閲ツールではありません。それは**解放者**. これにより、自由に考え、フィルターなしで推測し、頭に浮かぶことを全部ブレインダンプすることができます — つまり、未熟なアイデアがブログに載ってしまうことを恐れずに済む。

LLMはこの境界の守護者だ。 すべてを読む。 分類する。 生き残るに値するものを薄める。 秘密にしておくべきものを閉じ込める。 公開に適したものを作成する。

そして開発者は、最後の言葉を保つ：読み返す、挑戦する、検証する。判断する。

それはソロ開発者に欠けていた仕事の分担だった：精神的な事務処理を担当する合成従業員で、人間が最も得意とすること―設計、アーキテクチャ、意思決定―に集中できるようにする。

== 参考文献

* エイガー/レイジー エージェントのガバナンスに関する記事：link:../2026/0108_gouvernance_agent_opencode_eager_lazy_post.html[AsciiDocでAIエージェントを管理]
* 空間オントロジーと信頼の輪に関する記事：link:../2026/0114_gouvernance_cercles_confiance_ontologie_spatiale_alignement_llm_post.html[空間オントロジーとしてのアラインメントメカニズム]
* MVP0 匿名化ツールに関する記事：link:../2026/0115_anonymiseur_dataset_mvp0_realite_augmentee_llm_post.html[最初に雇用した人：データセットの匿名化ツール]
* 長いコンテキストのLLMの比較に関する記事：link:../2026/0112_comparaison_kimi_glm_deepseek_long_contexte_plugin_gradle_opencode_post.html[DeepSeek-V4-Pro, Kimi K2.6, GLM-5.1]
* エージェントバックアップメカニズムに関する記事 :link:../2026/0110_mecanisme_backup_contexte_agent_post.html[スライドウィンドウと寒波]
----&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;</description>
        </item><item>
            <title>私たちの最初の採用 : データセット匿名化ツール — MVP0、試用期間中</title>
            <link >https://cheroliv.com/blog/pilot-batch/0115_anonymiseur_dataset_mvp0_realite_augmentee_llm_post.html</link>
            <pubDate>Fri, 1 May 2026 00:00:00 +0000</pubDate>
            <guid isPermaLink="false">blog/pilot-batch/0115_anonymiseur_dataset_mvp0_realite_augmentee_llm_post.html</guid>
            <description>&amp;lt;div id=&amp;quot;toc&amp;quot; class=&amp;quot;toc&amp;quot;&amp;gt;
&amp;lt;div id=&amp;quot;toctitle&amp;quot;&amp;gt;Table des matières&amp;lt;/div&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel1&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_みんなが逃げ出す問題&amp;quot;&amp;gt;みんなが逃げ出す問題&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div id=&amp;quot;preamble&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;読了時間 : 12 minutes&amp;lt;/div&amp;gt;
&amp;lt;p&amp;gt;私はLLMを雇わない。私は匿名化の専門家を雇う。pgvectorを使ったRAGを行う前に、CDA/FPAの専門家をファインチューニングする前に、クライアントのワークスペースをプロビジョンする前に — 誰かがデータのトイレを掃除しなければならない。この従業員こそが、匿名化のエキスパート（codebase-gradleのMVP0、EPIC 2）だ。そして彼こそが製品を市場に適合させる人だ。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;dlist&amp;quot;&amp;gt;
&amp;lt;dl&amp;gt;
&amp;lt;dt class=&amp;quot;hdlist1&amp;quot;&amp;gt;チック&amp;lt;/dt&amp;gt;
&amp;lt;dd&amp;gt;
&amp;lt;p&amp;gt;(empty)&amp;lt;/p&amp;gt;
&amp;lt;/dd&amp;gt;
&amp;lt;/dl&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_みんなが逃げ出す問題&amp;quot;&amp;gt;みんなが逃げ出す問題&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;�訓練データを扱うAIスタートアップはすべて同じ壁にぶつかる：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-none hljs&amp;quot;&amp;gt;----
----
Données brutes client (SPG, cours, évaluations)
  ├→ Noms de stagiaires en clair dans les PDF
  ├→ Emails dans les métadonnées JSON
  ├→ IP de connexion dans les logs pgvector
  ├→ Identifiants dans les nœuds Graphify
  └→ Références OF pilote dans les schémas SQL
----

結果 : 汚いデータで RAG を行う（PII の幻覚、GDPR 違反、法的リスク）か、何もせず（製品なし）かのいずれかです。第三の道 — 手動でクリーニングする — はスケーラブルではありません。

私の答え : 問題を回避しない。L&amp;#39;**自動化する**。

== MVP0 : 匿名化ツール, 試用期間中に最初に雇用された

MVP0は機能ではありません。それは**利便性の専門家**— ピッチデッキでは誰も語りたがらない、汚くて愚かで残酷な仕事をする従業員。

それが行うこと：

[source]
----
ENTRÉE : Données brutes multi-sources
  ├→ AsciiDoc (SPG_A2SP.adoc) → noms, dates, OF pilote
  ├→ JSON (catalogue formations) → emails, téléphones
  ├→ YAML (config workspace) → tokens OAuth2
  ├→ SQL (schémas DDL) → IP, adresses
  ├→ pgvector (métadonnées embeddings) → identifiants
  ├→ ONNX (outputs classification) → noms propres
  └→ Graphify (graph.json) → nœuds avec PII

SORTIE : Datasets propres, format standardisé
  ├→ [ANONYMIZED] remplace les PII détectées
  ├→ Classification RGPD (niveau 0→4)
  ├→ Rapport d&amp;#39;audit (quoi a été nettoyé)
  └→ Dataset prêt pour RAG ET fine-tuning
----

最初に最も明白なパターンを検出します (emails`.*@.*`, トークン`sk-*`, `ghp_*`, IPs), それから彼は学ぶ。試用期間、それがそれです：偽陰性を見逃さないことを確認してから、彼を正式に採用します。

== このMVPが解き放つもの ( そしてそれは単なるコンプライアンスではない )

MVP0としての匿名化は、高速道路に入る前のGDPRの通行料ではない。それが高速道路そのものだ。それが開くものは次のとおりだ：

=== 現在 : プロンプトにおける拡張現実

[source]
----
DONNÉES BRUTES CLIENT
    ↓
Anonymiseur MVP0 → datasets propres
    ↓
RAG pgvector (MVP1) → top-K documents similaires (filtrés, anonymisés)
    ↓
LLM (deepseek-v4-pro) → réponse augmentée, zéro PII
----

RAGは汚れたデータを検索しません — それはスペースを検索します**構成上きれい**. これは回答の品質を大きく変える：LLMは認識しているが言及してはならないPIIを回避することに時間を費やさない。

=== 未来 : ファインチューニング on 健康なデータ

[source]
----
MVP0 → datasets propres accumulés (session après session)
    ↓
Fine-tuning expert métier (CDA, FPA) sur données zéro PII
    ↓
Modèle fine-tuné exposé via Ollama (sans fuite de données)
----

ファインチューニングは生データでの潜在的な法的災害です。クリーンなデータでは、それは**再現可能な方法**. 各クライアントはクリーニング済みのデータセットを蓄積し、各クライアントは自分のビジネス専門家を自分のデータでファインチューニングできます —  — 個人データを決して公開することはありません。

== なぜそれが販売可能なのか

これはGDPRコンプライアンスツールではありません。これは**普遍的な問題を資産に変える再現可能な方法**:

1. *すべてのトレーニング企業は汚れたデータを持っている* — それが問題だ
2. *誰も自動化されたマルチソースクリーニングパイプラインを持っていない* — これは市場です
3. *匿名化 → RAG → ファインチューニングのループは独自である* — それが障壁だ

Edster SaaS (MVP3)は« Gradleワークスペース »を販売しません。それはこの閉じたループを販売します。そしてMVP0は入口です。

== SQL形式はコンテキストの第三の方法

構造化データのインポートは単なる交換形式ではない。SQL スキーマ (DDL) は持ちます**ドメインのエンティティ-リレーションモデル**：

[source]
----
CREATE TABLE formation (
  id UUID PRIMARY KEY,
  titre VARCHAR NOT NULL,
  referentiel RNCP REFERENCES rncp(id),
  organisme OF REFERENCES of_pilote(id)  -- ← va être anonymisé
);
----

このDDLは、匿名化された後（行4）、LLMのコンテキストソースとなります。テキストではなく — du**ビジネスモデル**. RAGはベクトル類似性によるコンテンツを提供し、Graphifyは正確な構造による関係を提供し、SQLスキーマは**暗黙の Domain-Driven Design**: bounded contexts, agrégats, value objects. LLMはスキーマを読むことでドメインを理解します。

== ロードマップ：MVP0からSaaSまで

[source]
----
MVP0 — Anonymiseur (ce que cet article décrit)
  Sortie : datasets propres, reproductible

MVP1 — RAG pgvector (dépend de MVP0)
  Realité augmentée en prompt sur données nettoyées

MVP2 — Graphify + ONNX + SQL DDD (dépend de MVP1)
  Vecteur composite de contexte (règles + similarité + relations exactes)

MVP3 — SaaS Edster (dépend de MVP0-2)
  Provisionnement workspace client complet
----

各MVPは前のMVPに依存しています。MVP0がなければ、どのMVPもリリースできません。これがバックログにおいて「Anonymiseur」が「P0」ではない理由です — それは**MVP0**. これは最初の商業的な納品物であり、その他すべてはそれが成功することを条件としている。

== 結論：目に見えない仕事がすべてを可能にする

一般的なスタートアップでは、データのクレンジングはアウトソーシング、手動、または無視されます。このアーキテクチャでは、それは**製品の中心**. 匿名化者は最初に雇用される従業員です。なぜなら彼/彼女がいなければ、何も機能しないからです：

* MVP0 なし → 法的な RAG なし (MVP1)
* MVP0 がなければ → データ漏洩のないファインチューニングもできない (EPIC 5)
* MVP0 なし → 信頼できる SaaS なし (MVP3)
* MVP0がなければ → プロンプトに拡張現実がない
* MVP0 なし → コンテキストの第三の方法なし (SQL DDD)

彼は汚い仕事をしている。彼は決してピッチでは言及されない。だが、彼こそが工場を回している。

それが彼/彼女を最初に雇う理由です。

== 参考文献

* 空間オントロジーと信頼の輪に関する記事：link:../2026/0114_gouvernance_cercles_confiance_ontologie_spatiale_alignement_llm_post.html[空間オントロジーをアラインメントメカニズムとして]
* Eager/Lazyエージェントのガバナンスについての記事:link:../2026/0108_gouvernance_agent_opencode_eager_lazy_post.html[AsciiDocでAIエージェントを管理する]
* Hot/Warm/Cold メカニズムの記事:link:../2026/0110_mecanisme_backup_contexte_agent_post.html[スライドウィンドウと寒波]
* 3つのLLMの比較に関する記事 :link:../2026/0112_comparaison_kimi_glm_deepseek_long_contexte_plugin_gradle_opencode_post.html[DeepSeek-V4-Pro、Kimi K2.6、GLM-5.1]
----&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;</description>
        </item><item>
            <title>私たちの最初の採用：データセット匿名化ツール — MVP0 試用期間中</title>
            <link >https://cheroliv.com/blog/2026/0115_anonymiseur_dataset_mvp0_realite_augmentee_llm_post.html</link>
            <pubDate>Fri, 1 May 2026 00:00:00 +0000</pubDate>
            <guid isPermaLink="false">blog/2026/0115_anonymiseur_dataset_mvp0_realite_augmentee_llm_post.html</guid>
            <description>&amp;lt;div id=&amp;quot;toc&amp;quot; class=&amp;quot;toc&amp;quot;&amp;gt;
&amp;lt;div id=&amp;quot;toctitle&amp;quot;&amp;gt;Table des matières&amp;lt;/div&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel1&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_誰もが逃げ出す問題&amp;quot;&amp;gt;誰もが逃げ出す問題&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div id=&amp;quot;preamble&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;読書時間 : 12 minutes&amp;lt;/div&amp;gt;
&amp;lt;p&amp;gt;私はLLMを雇いません。匿名化者を雇います。pgvectorを使ったRAGの前に、CDA/FPAの専門家をファインチューニングする前に、クライアントのワークスペースをプロビジョニングする前に — だれかがデータのトイレを掃除しなければなりません。その従業員こそが匿名化の専門家（MVP0、EPIC 2、コードベース Gradle）です。そして彼が製品を市場向きにします。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;dlist&amp;quot;&amp;gt;
&amp;lt;dl&amp;gt;
&amp;lt;dt class=&amp;quot;hdlist1&amp;quot;&amp;gt;トック&amp;lt;/dt&amp;gt;
&amp;lt;dd&amp;gt;
&amp;lt;p&amp;gt;[]&amp;lt;/p&amp;gt;
&amp;lt;/dd&amp;gt;
&amp;lt;/dl&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_誰もが逃げ出す問題&amp;quot;&amp;gt;誰もが逃げ出す問題&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;トレーニングデータを扱うあらゆるAIスタートアップは、同じ壁にぶつかる：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-none hljs&amp;quot;&amp;gt;----
----
Données brutes client (SPG, cours, évaluations)
  ├→ Noms de stagiaires en clair dans les PDF
  ├→ Emails dans les métadonnées JSON
  ├→ IP de connexion dans les logs pgvector
  ├→ Identifiants dans les nœuds Graphify
  └→ Références OF pilote dans les schémas SQL
----

結果：汚れたデータに対してRAGを行う（PIIの幻覚、GDPR違反、法的リスク）か、何もせず（製品なし）かのいずれかです。第三の方法—手作業でクリーンアップする—はスケーラブルではありません。

私の答え：問題を回避しない。L&amp;#39;**自動化する**。

== MVP0：匿名化者、試用期間中に最初に採用された人

MVP0 は機能ではありません。それは**便利の専門家**— 一人の従業員が、汚い愚かで嫌な仕事をしており、誰もピッチデッキで話したがらない。

彼がやること:

[source]
----
ENTRÉE : Données brutes multi-sources
  ├→ AsciiDoc (SPG_A2SP.adoc) → noms, dates, OF pilote
  ├→ JSON (catalogue formations) → emails, téléphones
  ├→ YAML (config workspace) → tokens OAuth2
  ├→ SQL (schémas DDL) → IP, adresses
  ├→ pgvector (métadonnées embeddings) → identifiants
  ├→ ONNX (outputs classification) → noms propres
  └→ Graphify (graph.json) → nœuds avec PII

SORTIE : Datasets propres, format standardisé
  ├→ [ANONYMIZED] remplace les PII détectées
  ├→ Classification RGPD (niveau 0→4)
  ├→ Rapport d&amp;#39;audit (quoi a été nettoyé)
  └→ Dataset prêt pour RAG ET fine-tuning
----

最初に最も明白なパターンを検出します（emails`.*@.*`, トークン`sk-*`, `ghp_*`, IPs), それから彼は学ぶ。試用期間とはそういうことです : 偽陰性を見逃さないことを確認してから、正規に採用します。

== この MVP が解き放つもの（そしてそれは単なるコンプライアンスではない）

MVP0としての匿名化は、高速道路の前にあるGDPRの通行料ではなく、高速道路そのものです。それが高速道路そのものです。これがそれが開くもの：

=== 現在：プロンプトにおける拡張現実

[source]
----
DONNÉES BRUTES CLIENT
    ↓
Anonymiseur MVP0 → datasets propres
    ↓
RAG pgvector (MVP1) → top-K documents similaires (filtrés, anonymisés)
    ↓
LLM (deepseek-v4-pro) → réponse augmentée, zéro PII
----

RAGは汚れたデータの中で探さない―それは空間の中で探す**構築によってきれい**. これは回答の品質に大きな影響を与える：LLMは認識しているが言及すべきでないPIIを回避するために時間を費やすわけではない。

=== 将来 : 健全なデータへのファインチューニング

[source]
----
MVP0 → datasets propres accumulés (session après session)
    ↓
Fine-tuning expert métier (CDA, FPA) sur données zéro PII
    ↓
Modèle fine-tuné exposé via Ollama (sans fuite de données)
----

未加工のデータでのファインチューニングは法的災害となる可能性があります。クリーンなデータでは、それは**再現可能な方法**. 各クライアントは、クリーニングされたデータセットを蓄積し、各クライアントは自分のデータでビジネス専門家をファインチューニングできます —  — 絶対に個人データを露出することはありません。

== なぜそれが市場性があるのか

これは « GDPR コンプライアンス ツール » ではありません。これは一**普遍的な問題を資産に変える再現可能な方法**:

1. *すべてのトレーニング企業には汚いデータがあります* — それが問題です
2. *自動化されたマルチソースクリーニングパイプラインを持っているものはない* — それが市場です
3. ループ：匿名化 → RAG → ファインチューニングは独占的です — それが障壁です

Edster SaaS (MVP3)は「Gradle ワークスペース」を販売しません。それはこの閉じたループを販売します。そしてMVP0は入口です。

== コンテキストにおける第三の道としてのSQL形式

構造化データのインポートは単なる交換フォーマットではなく、SQLスキーマ(DDL)は**ドメイン エンティティ-リレーションシップ モデル** :

[source]
----
CREATE TABLE formation (
  id UUID PRIMARY KEY,
  titre VARCHAR NOT NULL,
  referentiel RNCP REFERENCES rncp(id),
  organisme OF REFERENCES of_pilote(id)  -- ← va être anonymisé
);
----

このDDLは、匿名化された後（行4）、LLMのコンテキストソースになります。テキストではない — これは**ビジネスモデル**. RAGはコンテンツ（ベクトル類似性）を提供し、Graphifyは関係（正確な構造）を提供し、SQLスキーマは**暗黙的ドメイン駆動設計**: bounded contexts, agrégats, value objects. LLMはスキーマを読むことでビジネスを理解する。

== ロードマップ：MVP0からSaaSへ

[source]
----
MVP0 — Anonymiseur (ce que cet article décrit)
  Sortie : datasets propres, reproductible

MVP1 — RAG pgvector (dépend de MVP0)
  Realité augmentée en prompt sur données nettoyées

MVP2 — Graphify + ONNX + SQL DDD (dépend de MVP1)
  Vecteur composite de contexte (règles + similarité + relations exactes)

MVP3 — SaaS Edster (dépend de MVP0-2)
  Provisionnement workspace client complet
----

各MVPは前のものに依存しています。MVP0なしではどのMVPも配信できません。これが、バックログにおける「Anonymiseur」が「P0」ではない理由です — それは**MVP0**. これは最初の商業的な納品物であり、それ以外のすべてはその成功にかかっている。

== 結論：すべてを可能にする見えない仕事

一般的なスタートアップでは、データのクリーニングは外部委託、手動、または無視されます。このアーキテクチャでは、それは**製品の中心**. 匿名化者は最初に雇用される従業員です。なぜなら、彼がいなければ何も機能しないからです :

* MVP0 がなければ → 法的な RAG なし (MVP1)
* MVP0なしで → データ漏洩なしではファインチューニングは行われない (EPIC 5)
* MVP0 なし→信頼できる SaaS なし(MVP3)
* MVP0 がなければ → プロンプトに拡張現実なし
* MVP0いないと→コンテキストにおける第三の道がない(SQL DDD)

彼は汚い仕事をする。ピッチで名前を挙げられることは決してない。しかし、工場を回しているのは彼だ。

それが理由で、最初に彼/彼女を雇う。

== 参考文献

* 空間オントロジーと信頼の円に関する記事：link:../2026/0114_gouvernance_cercles_confiance_ontologie_spatiale_alignement_llm_post.html[空間オントロジーとしての整合メカニズム]
* エージャー/ラジーなエージェントのガバナンスに関する記事 :link:../2026/0108_gouvernance_agent_opencode_eager_lazy_post.html[AsciiDocを使ってAIエージェントを管理する]
* Hot/Warm/Cold メカニズムに関する記事：link:../2026/0110_mecanisme_backup_contexte_agent_post.html[スライドウィンドウと寒波]
* 三つのLLMの比較に関する記事：link:../2026/0112_comparaison_kimi_glm_deepseek_long_contexte_plugin_gradle_opencode_post.html[DeepSeek-V4-Pro, Kimi K2.6, GLM-5.1]
----&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;</description>
        </item><item>
            <title>開発者の秘密の庭：空間オントロジーがプロンプトエンジニアリングなしでLLMをどのように調整するか</title>
            <link >https://cheroliv.com/blog/2026/0114_gouvernance_cercles_confiance_ontologie_spatiale_alignement_llm_post.html</link>
            <pubDate>Thu, 30 Apr 2026 00:00:00 +0000</pubDate>
            <guid isPermaLink="false">blog/2026/0114_gouvernance_cercles_confiance_ontologie_spatiale_alignement_llm_post.html</guid>
            <description>&amp;lt;div id=&amp;quot;toc&amp;quot; class=&amp;quot;toc&amp;quot;&amp;gt;
&amp;lt;div id=&amp;quot;toctitle&amp;quot;&amp;gt;Table des matières&amp;lt;/div&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel1&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_観察プロンプトエンジニアリングは砂の城だ&amp;quot;&amp;gt;観察：プロンプトエンジニアリングは砂の城だ&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_四つの信頼の円_空間的オントロジー&amp;quot;&amp;gt;四つの信頼の円 : 空間的オントロジー&amp;lt;/a&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel2&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_秘密の庭_cvs外の空間&amp;quot;&amp;gt;秘密の庭 : CVS外の空間&amp;lt;/a&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel3&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_gitignore_をガバナンス設定として&amp;quot;&amp;gt;.gitignore` をガバナンス設定として&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_スナップショットのメカニズム&amp;quot;&amp;gt;スナップショットのメカニズム&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_金庫_configuration_spring_cloud_configのように&amp;quot;&amp;gt;金庫 : &amp;lt;code&amp;gt;configuration/&amp;lt;/code&amp;gt; Spring Cloud Configのように&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_図書館_office_としてデータ消費可能&amp;quot;&amp;gt;図書館 : &amp;lt;code&amp;gt;office/&amp;lt;/code&amp;gt; としてデータ消費可能&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_鍛冶場_foundry_としての実装&amp;quot;&amp;gt;�鍛冶場: &amp;lt;code&amp;gt;foundry/&amp;lt;/code&amp;gt; としての実装&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_長所短所_空間アラインメント_対_プロンプトアラインメント&amp;quot;&amp;gt;長所/短所 : 空間アラインメント 対 プロンプトアラインメント&amp;lt;/a&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel2&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_クラシックアプローチプレプロンプトによるアラインメント&amp;quot;&amp;gt;クラシックアプローチ：プレプロンプトによるアラインメント&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_このアプローチ_空間オントロジーによるアラインメント&amp;quot;&amp;gt;このアプローチ : 空間オントロジーによるアラインメント&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_関係代数のワークスペースとデルタobservable&amp;quot;&amp;gt;関係代数のワークスペースとデルタObservable&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_コンテキスト複合ベクトル_rag_pgvector_graphify&amp;quot;&amp;gt;コンテキスト複合ベクトル : RAG + pgvector + Graphify&amp;lt;/a&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel2&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_コンポーネント_1_rag_langchain4j_postgresql_pgvector&amp;quot;&amp;gt;コンポーネント 1 — RAG LangChain4j + PostgreSQL pgvector&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_コンポーネント_2_knowledge_graph_graphify&amp;quot;&amp;gt;コンポーネント 2 — Knowledge Graph Graphify&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_コンポーネント_3_graphify_インクリメンタル_疎_集約可能_消費可能&amp;quot;&amp;gt;コンポーネント 3 — Graphify インクリメンタル : 疎, 集約可能, 消費可能&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_自動gdpr分類llmをルータとして&amp;quot;&amp;gt;自動GDPR分類：LLMをルータとして&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_ロードマップ_asciidoc_から_langgraph4j_へ&amp;quot;&amp;gt;ロードマップ : AsciiDoc から LangGraph4j へ&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_このアーキテクチャが解決することとそれが解決しないこと&amp;quot;&amp;gt;このアーキテクチャが解決すること（とそれが解決しないこと）&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_結論建築はディスコースとして&amp;quot;&amp;gt;結論：建築はディスコースとして&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_参考文献&amp;quot;&amp;gt;参考文献&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div id=&amp;quot;preamble&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;読了時間 : 20 minutes&amp;lt;/div&amp;gt;
&amp;lt;p&amp;gt;プロンプトエンジニアリングは脆いです。80,000トークンになると、あなたのアラインメントルールはノイズの中に埋もれ、LLMは会話の最初にあなたが求めたことを忘れます。私の解決策は？ テキストによるアラインメントではなく、&amp;lt;strong&amp;gt;スペース&amp;lt;/strong&amp;gt;. 私は開発ワークスペースを、内密な秘密の庭から公開の鍛冶場まで、4つの同心円状の信頼圏に構造化しました。各圏はファイルシステムの物理的な領域です。LLMはルールを思い出させる必要はありません；ファイルのパスがそれらを含みます。これがどのように機能するか、そしてなぜこの空間によるアラインメントアーキテクチャが、よりレジリエントであるかという話です。`system prompt`500行の。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;これは長い記事です。&amp;lt;br&amp;gt;
ゆっくりとお座りください。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;dlist&amp;quot;&amp;gt;
&amp;lt;dl&amp;gt;
&amp;lt;dt class=&amp;quot;hdlist1&amp;quot;&amp;gt;トック&amp;lt;/dt&amp;gt;
&amp;lt;dd&amp;gt;
&amp;lt;p&amp;gt;[]&amp;lt;/p&amp;gt;
&amp;lt;/dd&amp;gt;
&amp;lt;/dl&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_観察プロンプトエンジニアリングは砂の城だ&amp;quot;&amp;gt;観察：プロンプトエンジニアリングは砂の城だ&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;3週間、Opencodeを使ってGradleプラグインを開発しました。3つの異なるLLM、Kimi K2.6、GLM-5.1、DeepSeek-V4-Proを使用して（唯一の生存者ですが、これは別の話&amp;lt;a href=&amp;quot;0112_comparaison_kimi_glm_deepseek_long_contexte_plugin_gradle_opencode_post.html&amp;quot;&amp;gt;既にここで説明済み。&amp;lt;/a&amp;gt;）。私のエージェントガバナンス手法&amp;lt;a href=&amp;quot;0108_gouvernance_agent_opencode_eager_lazy_post.html&amp;quot;&amp;gt;以前の記事で詳しく説明しました。&amp;lt;/a&amp;gt;はAsciiDocファイルに基づいています —&amp;lt;code&amp;gt;AGENT.adoc&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;INDEX.adoc&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;PROMPT_REPRISE.adoc&amp;lt;/code&amp;gt;— 約30,000トークンのルール、バックログ、履歴を毎セッションの開始時に読み込む。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;それにもかかわらず、このドキュメントインフラストラクチャにもかかわらず、二つのことが私を驚かせました：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;olist arabic&amp;quot;&amp;gt;
&amp;lt;ol class=&amp;quot;arabic&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;LLMは忘れる。&amp;lt;/strong&amp;gt; EAGERファイルの先頭に絶対的なルールがあるにもかかわらず、累積トークン数が60,000を超えると（初期コンテキスト＋会話）、Kimi K2.6は提案し始めた`Write`エラーは構成ファイルに対して圧倒的だった。 GLM-5.1はFirebaseのトークンと置換すべきプレースホルダーを混同した。 ルールは書かれていた — LLMはそれらを*見なくなった*。&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;ガバナンスそのものが問題となる。 Hot/Warm/Cold&amp;lt;a href=&amp;quot;0110_mecanisme_backup_contexte_agent_post.html&amp;quot;&amp;gt;Article sur la rotation de backup.&amp;lt;/a&amp;gt; コンテキストの爆発を避けるために、しかし EAGERファイルはまだ1414行だった&amp;lt;a href=&amp;quot;0111_audit_contexte_agent_post.html&amp;quot;&amp;gt;J&amp;amp;#8217;ai documenté cet audit ici.&amp;lt;/a&amp;gt; ガバナンス — LLMの飽和から保護するために設計された — は、LLMを飽和させていた。&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ol&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;プロンプトのトークン数に依存しないアラインメント機構が必要でした。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;答え：テキストによって揃えるのをやめ、テキストによって揃え始める&amp;lt;strong&amp;gt;スペース&amp;lt;/strong&amp;gt;。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_四つの信頼の円_空間的オントロジー&amp;quot;&amp;gt;四つの信頼の円 : 空間的オントロジー&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;私のフォルダー`workspace/&amp;lt;code&amp;gt;(中に&amp;lt;/code&amp;gt;~/workspace/`) は &amp;lt;strong&amp;gt;pas&amp;lt;/strong&amp;gt; Git リポジトリではありません。 これは 私の仕事全体のルートです — コード、ドキュメント、トレーニング、インフラストラクチャ。 そしてこれは 4 つのゾーンに構造化されており、これらは単なる整理ルールではなく、しかしこれらは&amp;lt;strong&amp;gt;同心円状の信頼の円&amp;lt;/strong&amp;gt;：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;table class=&amp;quot;tableblock frame-all grid-all stretch&amp;quot;&amp;gt;
&amp;lt;colgroup&amp;gt;
&amp;lt;col style=&amp;quot;width: 6.6666%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 13.3333%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 20%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 26.6666%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 33.3335%;&amp;quot;&amp;gt;
&amp;lt;/colgroup&amp;gt;
&amp;lt;tbody&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;レベル&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;ラベル&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;物理的なゾーン&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;CVS&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;可視性&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;0&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;秘密の庭&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;`workspace/`根&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;何も&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;親密 — 考えは自由、コミットも公開もしない&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;1&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;金庫&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;code&amp;gt;configuration/&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;プライベートGit (ソロ)&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;秘密、トークン、ビジョンアーカイブ。一人だけ。&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;2&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;図書館&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;code&amp;gt;office/&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;Git プライベート (拡張)&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;教育データ, SPG/SPD, JSONスキーマ. 信頼の輪が識別されました。&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;4&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;公共の鍛冶場&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;code&amp;gt;foundry/&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;Git 公開 (Apache 2.0)&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;ソースコード、プラグイン、テスト、技術ドキュメント。&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/tbody&amp;gt;
&amp;lt;/table&amp;gt;
&amp;lt;div class=&amp;quot;admonitionblock note&amp;quot;&amp;gt;
&amp;lt;table&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;icon&amp;quot;&amp;gt;
&amp;lt;i class=&amp;quot;fa icon-note&amp;quot; title=&amp;quot;ℹ️&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;
&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;content&amp;quot;&amp;gt;
テーブルにレベル 3 はありません。レベル 3 は一時的なレベル &amp;lt;strong&amp;gt;transitoire&amp;lt;/strong&amp;gt; です：これはコンテンツの`office/`匿名化され、オープンデータとして公開する準備ができている。 物理的に固有の領域はなく — データの状態であり、場所ではない。
&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/table&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;各レベルは特定の質問に答えています：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;どこにアイデアを置けばいいのか、まだ共有する準備ができていない、たとえ小さな圈でも？&amp;lt;/strong&amp;gt; → 秘密の庭。Gitなし。プレッシャーなし。&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;APIトークンをどこに保存すれば漏洩しませんか？&amp;lt;/strong&amp;gt; → 金庫`configuration/`) 物理的に隔離されています。他のリポジトリが誤って参照することはありません。&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;コ・構築する研修カタログをパイロットのOFと共にどこで作るか？&amp;lt;/strong&amp;gt; → 図書館`office/`). バージョン管理され、コラボレーションが可能だが、プライベートな。&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;オープンソースのGradleプラグインを産業化する場所は？&amp;lt;/strong&amp;gt; → 鍛冶場`foundry/`). 公開、フォーク可能、CIでテスト済み。&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;このオントロジーは&amp;lt;strong&amp;gt;LLMで消費可能&amp;lt;/strong&amp;gt;. ファイルを読み込むときに`foundry/plantuml-gradle/src/`, 彼は暗黙的に知っている：「私はサークル4にいる — パブリックコード、必須テスト、秘密はなく、教育データもない」。 彼はそれを思い出させるプロンプトを必要としない。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_秘密の庭_cvs外の空間&amp;quot;&amp;gt;秘密の庭 : CVS外の空間&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;これは最も重要な概念 — そして最も反直感的な概念です。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;根`workspace/&amp;lt;code&amp;gt;ない&amp;lt;/code&amp;gt;.git/&amp;lt;code&amp;gt;. そこに住んでいるドキュメント (`WORKSPACE_VISION.adoc&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;WORKSPACE_AS_PRODUCT.adoc&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;WORKSPACE_ORGANIZATION.adoc&amp;lt;/code&amp;gt;— そして今あなたが読んでいるそれ（それに由来するものは）バージョン管理されたり、共有されたり、まして私以外によって読み返されたりすることを意図していません。これらは&amp;lt;strong&amp;gt;発芽中の思考&amp;lt;/strong&amp;gt;。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;admonitionblock important&amp;quot;&amp;gt;
&amp;lt;table&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;icon&amp;quot;&amp;gt;
&amp;lt;i class=&amp;quot;fa icon-important&amp;quot; title=&amp;quot;❗&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;
&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;秘密の庭は自然に &amp;lt;strong&amp;gt;out-of-CVS&amp;lt;/strong&amp;gt; です。バージョン管理の欠如が思考の自由の条件です。そこで書くのは読まれるため — 自分の考えを明確にするため。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/table&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;しかし、この自由には代償がある：一つ`rm`あれは偶然のことで、戦略的思考の何ヶ月分が消えてしまう。解決策は庭をバージョン管理することではない（それはそれを消すことになる）―それはそれを&amp;lt;strong&amp;gt;映す&amp;lt;/strong&amp;gt;最も制限された円の中で。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect3&amp;quot;&amp;gt;
&amp;lt;h4 id=&amp;quot;_gitignore_をガバナンス設定として&amp;quot;&amp;gt;.gitignore` をガバナンス設定として&amp;lt;/h4&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;の根底に`workspace/&amp;lt;code&amp;gt;, 1つのファイル&amp;lt;/code&amp;gt;.gitignore`最小が宣言する&amp;lt;strong&amp;gt;履歴管理ポリシー&amp;lt;/strong&amp;gt;秘密の庭のファイル:&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-none hljs&amp;quot;&amp;gt;.goosehints
.goose&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;Ce &amp;lt;code&amp;gt;.gitignore`クラシックなGit関数はありません（&amp;lt;/code&amp;gt;.git/`根元で). それは～のように振る舞う&amp;lt;strong&amp;gt;ガバナンス設定ファイル&amp;lt;/strong&amp;gt;正確な質問に答えるもの： &amp;lt;strong&amp;gt;秘密の庭の人工物で歴史化される価値があるものはどれか、そして純粋に一時的なものはどれか？&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;リストされたファイルの`.gitignore`—&amp;lt;code&amp;gt;.goosehints&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;.goose&amp;lt;/code&amp;gt;— エージェントによって生成される一時的なアーティファクト。戦略的価値はない。歴史化されない。&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;ファイル`.adoc`根の—&amp;lt;code&amp;gt;WORKSPACE_VISION.adoc&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;WORKSPACE_ORGANIZATION.adoc&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;WORKSPACE_AS_PRODUCT.adoc&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;WHAT_THE_GAMES_BEEN_MISSING.adoc&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;depots_implementes_strategie.adoc&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;synthese-LLMs-long-contexte.adoc&amp;lt;/code&amp;gt;— ではない&amp;lt;strong&amp;gt;ない&amp;lt;/strong&amp;gt;の中`.gitignore`これらは歴史化すべき遺物です。&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;Le `.gitignore`は&amp;lt;strong&amp;gt;ガバナンススキーマ&amp;lt;/strong&amp;gt;: そこにリストされていないものはすべてスナップショットの候補となる。そしてLLMはこのファイルを読むことで、アーカイブすべきものと無視できるものを正確に知っている——プロンプトで思い出させる必要がない。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect3&amp;quot;&amp;gt;
&amp;lt;h4 id=&amp;quot;_スナップショットのメカニズム&amp;quot;&amp;gt;スナップショットのメカニズム&amp;lt;/h4&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;作成しました`configuration/vision-archive/&amp;lt;code&amp;gt;: すべての日付付きスナップショット&amp;lt;/code&amp;gt;.adoc`ルートの、プライベートリポジトリにコミットされた`configuration/`. 各ブレインストーミングセッションはスナップショットを生成します：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;DATE=$(date +%Y-%m-%d)
mkdir -p /home/cheroliv/workspace/configuration/vision-archive/$DATE
cp /home/cheroliv/workspace/*.adoc /home/cheroliv/workspace/configuration/vision-archive/$DATE/
cd /home/cheroliv/workspace/configuration &amp;amp;amp;&amp;amp;amp; git add vision-archive/ &amp;amp;amp;&amp;amp;amp; \
  git commit -m &amp;quot;vision-archive: snapshot $DATE&amp;quot;&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;この手順は、セッションの終わりに、LLM自身によってトリガーされ、この全体的なルーティングタスクが実行されます。各スナップショットは、時刻Tにおける戦略的思考の完全な状態を捉えます。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;Gitの履歴の`configuration/`になる&amp;lt;strong&amp;gt;私の戦略的思考の伝記&amp;lt;/strong&amp;gt;. 私は一つを作ることができます`git log&amp;amp;#8201;&amp;amp;#8212;&amp;amp;#8201;vision-archive/`そして私のビジョンの進化を、セッションごとに、日付ごとに見る。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;作業日の後の履歴の実例：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-none hljs&amp;quot;&amp;gt;$ git -C configuration log --oneline -- vision-archive/
1089d1b vision-archive: fin de session finale 2026-05-03
6b21eaf vision-archive: fin de session 2026-05-03-1300
1690f82 vision-archive: post-article 2026-05-03
28e6593 vision-archive: post-migration 2026-05-03
3707b78 vision-archive: snapshot 2026-05-03 — jardin secret initial&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;1日で5つのスナップショット。それぞれが復元ポイント。それぞれが戦略の起源におけるマイルストーン。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;フォルダー`configuration/vision-archive/latest/`常に含んでいる&amp;lt;strong&amp;gt;作業コピー&amp;lt;/strong&amp;gt;最後のスナップショット、素早い参照として、Gitの履歴をナビゲートする必要なく。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;そしてLLMにとって、それは&amp;lt;strong&amp;gt;整合性のオラクル&amp;lt;/strong&amp;gt;: 彼が現在の実装と過去にアーカイブされたビジョンの間に矛盾を観測したとき、それを報告することができます。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_金庫_configuration_spring_cloud_configのように&amp;quot;&amp;gt;金庫 : &amp;lt;code&amp;gt;configuration/&amp;lt;/code&amp;gt; Spring Cloud Configのように&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;`configuration/`それは視覚のアーカイブだけを含んでいるわけではない。その第一の（および将来の）機能は、～であることだ。&amp;lt;strong&amp;gt;スプリングクラウドコンフィグサーバー&amp;lt;/strong&amp;gt;. すべてのシークレット、トークン、認証情報、およびインフラストラクチャの記述子は、ここに存在します。プライベートなGitリポジトリにあり、所有者だけがアクセスできます。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;なぜファイルではなく、別個のリポジトリを使うのか`.env`各プロジェクトで？&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;意図しないシークレットのプッシュ&amp;lt;/strong&amp;gt; :不可能です。シークレットは、公開プロジェクトが誤って参照できない非公開リポジトリにあります。&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;監査&amp;lt;/strong&amp;gt; : Gitの履歴は、設定の各変更の痕跡を示します。誰が何を、いつ変更したか、どのSHAハッシュを使用したか。&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;ロールバック&amp;lt;/strong&amp;gt; :`git revert`� 壊れた構成上で。 スナップショット、手動バックアップなし。&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_図書館_office_としてデータ消費可能&amp;quot;&amp;gt;図書館 : &amp;lt;code&amp;gt;office/&amp;lt;/code&amp;gt; としてデータ消費可能&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;`office/`それは開発作業のドキュメンテーションの対応である。それはブログ記事、技術仕様、トレーニング教材（FPA、SPG/SPD の 38 のコースディレクトリ、JSON スキーマ、Bloom/Harrow/Krathwohl のタクソノミー）を含んでいる — それが構成するものすべてである。&amp;lt;strong&amp;gt;教育教材&amp;lt;/strong&amp;gt;。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;しかし`office/`単なるドキュメントの引き出しではない。それは&amp;lt;strong&amp;gt;構造化データのソース&amp;lt;/strong&amp;gt;Gradle プラグインの`foundry/`消費しています。ブログ記事の中に`office/`は、プラグインによってHTMLに変換されるエントリです。AsciiDocのSPGは`office/metiers/FPA/`これは、オーケストレーターがパースしてスライド、クイズ、およびビデオカプセルを生成するアーティファクトです。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;Et le `build.gradle.kts`根本に`office/`ビジネスコードではありません — それは&amp;lt;strong&amp;gt;プラグインエコシステムの消費スクリプト&amp;lt;/strong&amp;gt;. 彼は言う： 「私が使っているGradleプラグインはこちらです、ワークスペースのコンテキストはこちらです」&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_鍛冶場_foundry_としての実装&amp;quot;&amp;gt;�鍛冶場: &amp;lt;code&amp;gt;foundry/&amp;lt;/code&amp;gt; としての実装&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;code&amp;gt;foundry/`を含む&amp;lt;strong&amp;gt;工業化されたコード&amp;lt;/strong&amp;gt;. 54 Git リポジトリ, そのうち 7 は現在、によって管理されている&amp;lt;/code&amp;gt;.agents/`. ここがビジョンが実行可能になる場所 — Gradleプラグイン、CI/CD、JUnit5 + Cucumberのテスト。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;との関係`office/`は双方向です：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;code&amp;gt;office/&amp;lt;/code&amp;gt;→&amp;lt;code&amp;gt;foundry/&amp;lt;/code&amp;gt;: 教育データはプラグインが消費する原材料です。&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;code&amp;gt;foundry/&amp;lt;/code&amp;gt;→&amp;lt;code&amp;gt;office/&amp;lt;/code&amp;gt;：プラグインは豊かにするデータを生成する`office/` — le `graph.json`graphify-gradleのコンパイル済みスライダーデッキ、ビルドレポート&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_長所短所_空間アラインメント_対_プロンプトアラインメント&amp;quot;&amp;gt;長所/短所 : 空間アラインメント 対 プロンプトアラインメント&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;2つのアプローチを比較しましょう。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_クラシックアプローチプレプロンプトによるアラインメント&amp;quot;&amp;gt;クラシックアプローチ：プレプロンプトによるアラインメント&amp;lt;/h3&amp;gt;
&amp;lt;table class=&amp;quot;tableblock frame-all grid-all stretch&amp;quot;&amp;gt;
&amp;lt;colgroup&amp;gt;
&amp;lt;col style=&amp;quot;width: 20%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 80%;&amp;quot;&amp;gt;
&amp;lt;/colgroup&amp;gt;
&amp;lt;tbody&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;�✅ プロ&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;❌ 反対&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;実装が簡単です。 システムプロンプト内のテキストブロック。&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;長いコンテキストでは脆弱&amp;lt;/strong&amp;gt; : ルールは80Kトークン以降で見失われる。&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;一般的な規則（トーン、フォーマット）に機能します。&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;検証不可能&amp;lt;/strong&amp;gt; : LLMがルールを破るのを妨げるものは何もない。&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;プロジェクトのアーキテクチャを考え直す必要はありません。&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;�譲渡不能&amp;lt;/strong&amp;gt; : 各リポジトリはルールを再宣言する。&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;純粋に宣言的&amp;lt;/strong&amp;gt; : LLMはそれがすべきだと知っているが、何もそれを妨げない。&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/tbody&amp;gt;
&amp;lt;/table&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_このアプローチ_空間オントロジーによるアラインメント&amp;quot;&amp;gt;このアプローチ : 空間オントロジーによるアラインメント&amp;lt;/h3&amp;gt;
&amp;lt;table class=&amp;quot;tableblock frame-all grid-all stretch&amp;quot;&amp;gt;
&amp;lt;colgroup&amp;gt;
&amp;lt;col style=&amp;quot;width: 20%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 80%;&amp;quot;&amp;gt;
&amp;lt;/colgroup&amp;gt;
&amp;lt;tbody&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;�✅ プロ&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;❌ 反対&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;長文コンテキストに対してレジリエント&amp;lt;/strong&amp;gt; : ルールはファイルパスにあり、遠いプロンプトにはない。&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;初期インフラストラクチャコスト&amp;lt;/strong&amp;gt; : ワークスペースを円形に構成するには時間がかかります。&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;機械的に検証可能&amp;lt;/strong&amp;gt; : 秘密の中`foundry/&amp;lt;code&amp;gt;によって検出可能`git check-ignore&amp;lt;/code&amp;gt;.&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;規律が必要&amp;lt;/strong&amp;gt; : 新しい貢献者は円を理解する必要がある。&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;Transférable&amp;lt;/strong&amp;gt; : 一つ`AGENT.adoc`標準は、すべての新しいプロジェクトにサークルを公開します。&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;空間的制約のみをカバー&amp;lt;/strong&amp;gt; — コードスタイルはプロンプトに残る。&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;設計によるセキュリティ&amp;lt;/strong&amp;gt; : 一つ`git push`以来`foundry/&amp;lt;code&amp;gt;公開できない`configuration/&amp;lt;/code&amp;gt;。&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;LLM以外のエージェントによって消費可能&amp;lt;/strong&amp;gt; : Gradleオーケストレーターはサークルに従ってルーティングできます。&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/tbody&amp;gt;
&amp;lt;/table&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;主な利益は守備的（セキュリティ、可視性）ではなく — それは&amp;lt;strong&amp;gt;クリエイティブ&amp;lt;/strong&amp;gt;. LLMがオントロジーによって構造化された空間で作業しているとき、それはどのプロンプトでも許されないことをすることができる：&amp;lt;strong&amp;gt;デルタを観察する&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_関係代数のワークスペースとデルタobservable&amp;quot;&amp;gt;関係代数のワークスペースとデルタObservable&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;LLMが巡回するとき`foundry/&amp;lt;code&amp;gt;, それはあるを持っている&amp;lt;strong&amp;gt;構造化データの格子&amp;lt;/strong&amp;gt;ノード (プラグイン、ファイル、テスト、依存関係)、型付きエッジ (`import&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;depends_on&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;generates&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;tests&amp;lt;/code&amp;gt;), 構成関係と順序関係 (`training-gradle`リポジトリを抽出→`slider-gradle`スライドを生成します →`capsule-gradle`動画を編集して&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;この代数はどこにも平文で書かれていない — しかし、それは*観測可能*である。それぞれ`build.gradle.kts`依存関係を公開します。それぞれ`INDEX.adoc`相互参照を表示します。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;LLMはこの代数を観察し、それを検出する&amp;lt;strong&amp;gt;デルタ&amp;lt;/strong&amp;gt;システムがすでに生産できるものと、ビジョンが描写するものの間のギャップ&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;このデルタから、彼は(または、それは)いくつかの&amp;lt;strong&amp;gt;業務エキスパートの地図&amp;lt;/strong&amp;gt;— CDA (アプリケーション設計開発者、Kotlin/Gradle/JHipster) と FPA (成人向けプロフェッショナル講師、教育法/Qualiopi/Bloom) — 各専門家に不足しているものを特定する。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-none hljs&amp;quot;&amp;gt;Expert CDA (Kotlin/Gradle/JHipster)
  ├── Plugins : jhipster-gradle-plugins, plantuml-gradle,
  │   codebase-gradle
  ├── Delta : pas encore de SPG CDA formalisé,
  │   pas de fine-tuning expert CDA

Expert FPA (Pédagogie/Qualiopi/Bloom)
  ├── Plugins : training-gradle, slider-gradle,
  │   school-backoffice/forms, capsule-gradle
  ├── Matériel : 38 modules cours, SPG/SPD, taxonomies
  └── Delta : parser AsciiDoc→JSON à créer,
      orchestrateur à coder&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;LLMに何をすべきかを教える必要はない。デルタは構造から現れる。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_コンテキスト複合ベクトル_rag_pgvector_graphify&amp;quot;&amp;gt;コンテキスト複合ベクトル : RAG + pgvector + Graphify&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;リレーショナル代数は理論的な構築ではありません。それは*具体化された*三つのコンポーネントによって一つの&amp;lt;strong&amp;gt;コンテキストの合成ベクトル&amp;lt;/strong&amp;gt;LLMのために&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_コンポーネント_1_rag_langchain4j_postgresql_pgvector&amp;quot;&amp;gt;コンポーネント 1 — RAG LangChain4j + PostgreSQL pgvector&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;私はすでにLangChain4jを2つのプラグインで本番環境で使用しています：&amp;lt;code&amp;gt;slider-gradle&amp;lt;/code&amp;gt;(4 providers LLM) と`plantuml-gradle`(7 プロバイダー). ONNX の埋め込み (AllMiniLmL6V2) データのインデックスを`office/`そしてソースコードの`foundry/`PostgreSQL + pgvector の中で。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;このRAGは2つの次元で機能します：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;Dimension data&amp;lt;/strong&amp;gt; : ドキュメント`office/`(SPG, 記事, 形成, JSONスキーマ)&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;ディメンションコード&amp;lt;/strong&amp;gt;:コードベース`foundry/`(Kotlinのソース, Cucumberのテスト, AGENT.adoc)&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;交差は、&amp;lt;strong&amp;gt;何&amp;lt;/strong&amp;gt;（業務ドメイン）と*方法*（実装）の両方をカバーします。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_コンポーネント_2_knowledge_graph_graphify&amp;quot;&amp;gt;コンポーネント 2 — Knowledge Graph Graphify&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;Graphifyは組み込まれています`plantuml-gradle`(109 tests, 380/380 PASS)と生成する`graph.json`— ノード、エッジ、および自動検出されたコミュニティを持つ構造化されたナレッジグラフ&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;RAGがベクトル類似性（ぼやけた）によって動作するのに対し、知識グラフは…で動作する&amp;lt;strong&amp;gt;正確な関係&amp;lt;/strong&amp;gt;(決定的) :`graphify query`意味的なクエリについて (約50トークン),`graphify path`ナビゲートする,`graphify explain`説明するために。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_コンポーネント_3_graphify_インクリメンタル_疎_集約可能_消費可能&amp;quot;&amp;gt;コンポーネント 3 — Graphify インクリメンタル : 疎, 集約可能, 消費可能&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;これが建築上の重要な決定です。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;Graphify は単一のリポジトリに存在してはなりません。それはある方法で生きなければならない。&amp;lt;strong&amp;gt;散らばった&amp;lt;/strong&amp;gt;各プラグインで :&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;olist arabic&amp;quot;&amp;gt;
&amp;lt;ol class=&amp;quot;arabic&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;各プラグイン&amp;lt;/strong&amp;gt; は Gradle タスクを含む`updateKnowledgeGraph`Graphifyを呼び出す&amp;lt;strong&amp;gt;自身のスコープで&amp;lt;/strong&amp;gt;と生成する一つ`graph.json`ローカル。&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;* ビルドスクリプトの`office/&amp;lt;code&amp;gt;* 消費する`graphify-gradle`と`rootDir = /home/cheroliv/workspace`そして生成する`graph.json&amp;lt;/code&amp;gt; &amp;lt;strong&amp;gt;グローバル&amp;lt;/strong&amp;gt;ローカルグラフを集約する&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;*各プラグインのRAG*を注入する`graph.json`グローバルのように&amp;lt;strong&amp;gt;コンテキストフィルター&amp;lt;/strong&amp;gt;LLMのクエリに対して&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ol&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-none hljs&amp;quot;&amp;gt;TÂCHE GRADLE (dans chaque plugin)
    ↓
graphify → graph.json (scope local)
    ↓
office/build.gradle.kts → graph.json (scope global)
    ↓
RAG pgvector (dans slider, plantuml, codebase...)
    ↓  ← injection du graph.json comme filtre
LLM (deepseek-v4-pro)
    ↓  ← observation algèbre relationnelle
    ↓  ← détection delta vs cartographies experts
PRIORISATION → prochaine tâche&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;結果：LLMは虚空を探さず、ナレッジグラフによって構造化された空間をナビゲートします。 「&amp;lt;code&amp;gt;génère un diagramme&amp;lt;/code&amp;gt;」というクエリは、グラフの関連ノードに到達できます。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_自動gdpr分類llmをルータとして&amp;quot;&amp;gt;自動GDPR分類：LLMをルータとして&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;空間オントロジーはLLMを単に整列させるだけで満足せず — それに___を与える&amp;lt;strong&amp;gt;GDPRの分類グリッド&amp;lt;/strong&amp;gt;各データをその正当なゾーンにルーティングするために。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;table class=&amp;quot;tableblock frame-all grid-all stretch&amp;quot;&amp;gt;
&amp;lt;colgroup&amp;gt;
&amp;lt;col style=&amp;quot;width: 12.5%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 37.5%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 25%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 25%;&amp;quot;&amp;gt;
&amp;lt;/colgroup&amp;gt;
&amp;lt;tbody&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;基準&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;LLM検出&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;アクション&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;最大レベル&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;個人データ (名前、メール、IP)&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;パターン`@`, IP, 固有名詞&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;�匿名化 →`[OF_PILOTE]`またはレベル2のルーター&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;2&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;トークン / シークレット / クレデンシャル&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;パターン`sk-&amp;amp;#8230;&amp;amp;#8203;&amp;lt;code&amp;gt;, `ghp_&amp;amp;#8230;&amp;amp;#8203;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ya29&amp;amp;#8230;&amp;amp;#8203;&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;ルーター →&amp;lt;code&amp;gt;configuration/&amp;lt;/code&amp;gt;. 参照元`${VAR}`コード内で。&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;1&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;内部URL&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;含む`localhost`, プライベートIP&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;匿名化 →&amp;lt;code&amp;gt;${API_URL}&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;2&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;教育データ (SPG, コース)&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;構造 Bloom/Qualiopi&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;ルーター →&amp;lt;code&amp;gt;office/&amp;lt;/code&amp;gt;(レベル 2). エクスポート時はダブルバージョン。&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;3&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;ソースコード / テスト&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;拡張`.kt`, &amp;lt;code&amp;gt;.kts`中`foundry/&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;ルーター →&amp;lt;code&amp;gt;foundry/&amp;lt;/code&amp;gt;. 秘密がないことを確認してください。&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;4&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/tbody&amp;gt;
&amp;lt;/table&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;セッションの最後に、LLMは実行する&amp;lt;strong&amp;gt;グローバルタスク&amp;lt;/strong&amp;gt;:&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;olist arabic&amp;quot;&amp;gt;
&amp;lt;ol class=&amp;quot;arabic&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;の読み込み`.gitignore`スナップショットから除外する一時的なアーティファクトと、履歴化する戦略的なアーティファクトを識別するためのルート&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;すべてのファイルのインベントリ`.adoc`根の`workspace/`&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;フィルタリング：リストされたファイルの除外`.gitignore`, すべての他を含む&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;中にコピー`configuration/vision-archive/$DATE/&amp;lt;code&amp;gt;とシンボリックリンクの更新`latest/&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;リポジトリへのコミット`configuration/`構造化されたメッセージと共に&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;各変更ファイルの自動GDPR分類（すべての円）&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;ルーティング : データ`office/&amp;lt;code&amp;gt;→ プライベートコミット, コード`foundry/&amp;lt;/code&amp;gt;→&amp;lt;code&amp;gt;./gradlew check&amp;lt;/code&amp;gt;, 構成 → コミット&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;構造化されたレポートとRGPDアラートおよびアーカイブの確認&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ol&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;Le `.gitignore`ルートはGitの設定ファイルではありません — それは&amp;lt;strong&amp;gt;履歴管理のガバナンスファイル&amp;lt;/strong&amp;gt;. それはLLMが消費するスキーマを定義し、どの秘密の庭のファイルが戦略的伝記に入り、どれが捨てられるかを決定します。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;LLMはもはや単なるテキスト生成器ではなくなった。それは&amp;lt;strong&amp;gt;情報管理者&amp;lt;/strong&amp;gt;エコシステムの — 生産者、分類器、ルーター。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_ロードマップ_asciidoc_から_langgraph4j_へ&amp;quot;&amp;gt;ロードマップ : AsciiDoc から LangGraph4j へ&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;今日、このガバナンスは &amp;lt;strong&amp;gt;決定論的&amp;lt;/strong&amp;gt; です : LLM は AsciiDoc ファイルに記述された手順を適用します。これは&amp;lt;strong&amp;gt;フェーズ 1&amp;lt;/strong&amp;gt;— LLMメモリを用いたプロンプトエンジニアリング。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;La &amp;lt;strong&amp;gt;フェーズ 2&amp;lt;/strong&amp;gt;それぞれの手順をあるものの中に抽出する&amp;lt;strong&amp;gt;型付き Gradle タスク&amp;lt;/strong&amp;gt; :&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-none hljs&amp;quot;&amp;gt;./gradlew endSessionWorkspace    → snapshot vision-archive
./gradlew endSessionProject      → archive .agents/
./gradlew endSessionReport       → rapport multi-zones&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;La &amp;lt;strong&amp;gt;フェーズ 3&amp;lt;/strong&amp;gt;セッション終了プロセスをあるもののようにモデル化する&amp;lt;strong&amp;gt;状態グラフ&amp;lt;/strong&amp;gt;とhttps://github.com/langgraph4j/langgraph4j[LangGraph4j]:&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-none hljs&amp;quot;&amp;gt;[Start] → [Inventaire fichiers modifiés]
       → [Classification RGPD] (nœud ONNX)
       → [Branchement par cercle]
            ├→ cercle 0 → snapshot → commit
            ├→ cercle 2 → anonymisation → commit
            ├→ cercle 4 → archive → commit
            └→ cercle 1 → commit configuration/
       → [Rapport] → [End]&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;このグラフは CI/CD でバージョン管理され、Gradle で実行され、プラグインの GitHub Secrets を介して設定されます。LLM はルーティングを決定する必要がなくなり — グラフがそれを行います。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_このアーキテクチャが解決することとそれが解決しないこと&amp;quot;&amp;gt;このアーキテクチャが解決すること（とそれが解決しないこと）&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;admonitionblock caution&amp;quot;&amp;gt;
&amp;lt;table&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;icon&amp;quot;&amp;gt;
&amp;lt;i class=&amp;quot;fa icon-caution&amp;quot; title=&amp;quot;🔒&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;
&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;空間オントロジーはすべてをカバーしない。 コードスタイルの規約、命名、アーキテクチャ設計の選択 — これらはすべてプロンプトに残る。 空間オントロジーが解決するのは、&amp;lt;strong&amp;gt;セキュリティ・可視性レイヤー&amp;lt;/strong&amp;gt;各バイトが存在すべき場所と、それを見ることができる者。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/table&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;これは彼女が具体的に提供するものです：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;olist arabic&amp;quot;&amp;gt;
&amp;lt;ol class=&amp;quot;arabic&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;ない`git push`偶発的な秘密&amp;lt;/strong&amp;gt; : 秘密は`configuration/&amp;lt;code&amp;gt;(サークル 1). 公共プロジェクトは`foundry/&amp;lt;/code&amp;gt;(円4)。両方を横切る道はない。&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;業務コードはデータに含まれません&amp;lt;/strong&amp;gt; :`office/&amp;lt;code&amp;gt;含む&amp;lt;/code&amp;gt;.adoc`, YAML, JSON スキーマ — ただし`.kt`. Le `build.gradle.kts`そこで暮らしているのは消費スクリプト、 ビジネスコードではありません。&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;戦略的思考が明らかにされていない&amp;lt;/strong&amp;gt; : ビジョンのドキュメントは秘密の庭に生きています（CVS外のルート）。スナップショットは`configuration/`(私的な金庫)。信頼の輪を広げても、誰も戦略の創成を読まない。&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;自動優先化&amp;lt;/strong&amp;gt; : LLM は、関係代数（存在するもの）とエキスパートマッピング（必要なもの）の間のデルタを観測します。次の開発タスクはこのデルタから生じます。&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ol&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_結論建築はディスコースとして&amp;quot;&amp;gt;結論：建築はディスコースとして&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;私はサイトのフッターに政治的マニフェストを掲載しません。 私はプロンプトに倫理的なルールを入れません。 アライメントはテキストの中にない——それは中にある&amp;lt;strong&amp;gt;ファイルシステム&amp;lt;/strong&amp;gt;。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;LLM がこの空間で作業しているとき、秘密を漏らすことはできません（経路がそれを防ぐため）。教育データとソースコードを混同することはできません（物理的な領域が異なるため）。80,000 トークンのセキュリティ ルールを忘れることはできません——なぜなら、そのルールはプロンプトの中ではなく、そこにあるからです。&amp;lt;code&amp;gt;workspace/&amp;lt;/code&amp;gt;→&amp;lt;code&amp;gt;configuration/&amp;lt;/code&amp;gt; → &amp;lt;code&amp;gt;office/&amp;lt;/code&amp;gt;→`foundry/`それぞれのファイルの読み込みは反応性がある。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;これは、*secure by design*の原則をエージェントのアラインメントに適用したものです：LLMにルールを覚えさせないようにする。アーキテクチャによってエラーが構造的に不可能となるようにする。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;そして、これはLLMに与えるもので、どのプロンプトにも与えることができないもの：能力を&amp;lt;strong&amp;gt;感じ取る&amp;lt;/strong&amp;gt;彼がどこにいるか、何が存在し、何が欠けているか — そしてそれらから何をすべきかを導き出す。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_参考文献&amp;quot;&amp;gt;参考文献&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;エージェントのEager/Lazyガバナンスに関する記事：&amp;lt;a href=&amp;quot;../2026/0108_gouvernance_agent_opencode_eager_lazy_post.html&amp;quot;&amp;gt;AsciiDocを使ってAIエージェントを管理する&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;Hot/Warm/Coldメカニズムに関する記事 :&amp;lt;a href=&amp;quot;../2026/0110_mecanisme_backup_contexte_agent_post.html&amp;quot;&amp;gt;スライドウィンドウと寒波&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;コンテキスト監査に関する記事：&amp;lt;a href=&amp;quot;../2026/0111_audit_contexte_agent_post.html&amp;quot;&amp;gt;自分のガバナンスが問題になるとき&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;3つのLLMの比較に関する記事：&amp;lt;a href=&amp;quot;../2026/0112_comparaison_kimi_glm_deepseek_long_contexte_plugin_gradle_opencode_post.html&amp;quot;&amp;gt;DeepSeek-V4-Pro, Kimi K2.6, GLM-5.1&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;</description>
        </item><item>
            <title>Supabase から Firebase への移行：Firestore にバックエンドなしでお問い合わせフォームを接続</title>
            <link >https://cheroliv.com/blog/2026/0113_integration_firebase_contact_form_post.html</link>
            <pubDate>Wed, 29 Apr 2026 00:00:00 +0000</pubDate>
            <guid isPermaLink="false">blog/2026/0113_integration_firebase_contact_form_post.html</guid>
            <description>&amp;lt;div id=&amp;quot;toc&amp;quot; class=&amp;quot;toc&amp;quot;&amp;gt;
&amp;lt;div id=&amp;quot;toctitle&amp;quot;&amp;gt;Table des matières&amp;lt;/div&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel1&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_シーン何も保存しないフォーム&amp;quot;&amp;gt;シーン：何も保存しないフォーム&amp;lt;/a&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel2&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_supabaseの遺産&amp;quot;&amp;gt;Supabaseの遺産&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_幽霊の二重提出&amp;quot;&amp;gt;幽霊の二重提出&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_なぜfirebaseをsupabaseの代わりに使うのか&amp;quot;&amp;gt;なぜFirebaseをSupabaseの代わりに使うのか？&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_フェーズ_1_firebase_プロジェクトを作成&amp;quot;&amp;gt;フェーズ 1 : Firebase プロジェクトを作成&amp;lt;/a&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel2&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_初期化&amp;quot;&amp;gt;初期化&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_firestoreセキュリティルール&amp;quot;&amp;gt;Firestoreセキュリティルール&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_フェーズ_2_提出のjavascriptを書き直す&amp;quot;&amp;gt;フェーズ 2: 提出のJavaScriptを書き直す&amp;lt;/a&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel2&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_依存関係_window_firebase&amp;quot;&amp;gt;依存関係 `window.&amp;lt;em&amp;gt;FIREBASE&amp;lt;/em&amp;gt;&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_新しい_contact_js&amp;quot;&amp;gt;新しい `contact.js&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_phase_3_supabaseのデッドコードをクリーンアップ&amp;quot;&amp;gt;Phase 3 : Supabaseのデッドコードをクリーンアップ&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_フェーズ_4_フッターを設定する&amp;quot;&amp;gt;フェーズ 4: フッターを設定する&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_フェーズ_5_最終アーキテクチャ&amp;quot;&amp;gt;フェーズ 5 : 最終アーキテクチャ&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_この移行がドッグフーディングについて何を言っているか&amp;quot;&amp;gt;この移行がドッグフーディングについて何を言っているか&amp;lt;/a&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel2&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_変更のまとめ&amp;quot;&amp;gt;変更のまとめ&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_次のステップ_バックログ&amp;quot;&amp;gt;次のステップ (バックログ)&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_参考文献&amp;quot;&amp;gt;参考文献&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div id=&amp;quot;preamble&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;読了時間 : 12 minutes&amp;lt;/div&amp;gt;
&amp;lt;p&amp;gt;数ヶ月間、このサイトのお問い合わせフォームは &amp;lt;code&amp;gt;mock JavaScript&amp;lt;/code&amp;gt; 上で動いていました — 85% の成功率を約束するもの、偽の &amp;lt;code&amp;gt;Firestore&amp;lt;/code&amp;gt;、データはゼロ、保存されていない。当初の計画では、メール通知のために &amp;lt;code&amp;gt;Supabase&amp;lt;/code&amp;gt; バックエンドと &amp;lt;code&amp;gt;Google Apps Script&amp;lt;/code&amp;gt; を組み合わせる予定でした。断念されました。今日、私は &amp;lt;code&amp;gt;Firebase Firestore&amp;lt;/code&amp;gt; への移行について語ります： &amp;lt;code&amp;gt;projet&amp;lt;/code&amp;gt; の作成、 &amp;lt;code&amp;gt;règles de sécurité&amp;lt;/code&amp;gt; の設定、 &amp;lt;code&amp;gt;JS&amp;lt;/code&amp;gt; の書き換え、 &amp;lt;code&amp;gt;Supabase&amp;lt;/code&amp;gt; のデッドコードの削除。そしてなぜこの選択が開発哲学におけるより広い意味を示すのか。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;dlist&amp;quot;&amp;gt;
&amp;lt;dl&amp;gt;
&amp;lt;dt class=&amp;quot;hdlist1&amp;quot;&amp;gt;チック&amp;lt;/dt&amp;gt;
&amp;lt;dd&amp;gt;
&amp;lt;p&amp;gt;[]&amp;lt;/p&amp;gt;
&amp;lt;/dd&amp;gt;
&amp;lt;/dl&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_シーン何も保存しないフォーム&amp;quot;&amp;gt;シーン：何も保存しないフォーム&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;このサイトはJBakeによって生成されています。私のGradleプラグインです。&amp;lt;code&amp;gt;bakery&amp;lt;/code&amp;gt;. これは100％静的です — バックエンドもデータベースもありません。ただし、お問い合わせフォームがあります。このページ`contact.html`存在し、HTMLは準備完了です（項目：名前、メール、電話番号、件名、メッセージ、HTML5検証、スパム防止ハニーポット）、Bootstrapのスタイルは設定済みです。見た目では、すべて完璧です。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;ただし、提出すると何も起こらない。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-javascript hljs&amp;quot; data-lang=&amp;quot;javascript&amp;quot;&amp;gt;const firebaseMock = new Promise((resolve, reject) =&amp;amp;gt; {
    setTimeout(() =&amp;amp;gt; {
        if (Math.random() &amp;amp;lt; 0.85) {
            resolve({ status: 201, message: &amp;#39;Message stored in Firestore.&amp;#39; });
        } else {
            reject({ status: 500, message: &amp;#39;Firestore write failed.&amp;#39; });
        }
    }, 1500);
});&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;モック。見せかけの約束。ユーザーはスピナーを見、次に「メッセージが正常に送信されました！」というメッセージを見る。しかしデータは虚空に消える。どこにもメッセージは保存されない。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;状況は壊れたフォームよりも悪い — それは嘘をつくフォームだ。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_supabaseの遺産&amp;quot;&amp;gt;Supabaseの遺産&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;初期計画、文書化されたで`content/draft/integration_formulaire_contact_supabase.adoc`, 予定していた :&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;olist arabic&amp;quot;&amp;gt;
&amp;lt;ol class=&amp;quot;arabic&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;Supabaseのデータベースとテーブル`contacts`と Row Level Security&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;1つのRPC`handle_contact_form`サーバー サイド&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;Google Apps Script のウェブフックを呼び出す SQL トリガー&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;Gmail の通知メールを送信する Google Apps Script&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ol&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;対応するJavaScriptコードはまだ存在しています`script.js`. クラスがあります`SupabaseManager`グローバル変数を使用してSupabaseクライアントを初期化する`SUPABASE_URL` et &amp;lt;code&amp;gt;SUPABASE_KEY&amp;lt;/code&amp;gt;, とクラス`ContactFormHandler`フォームのsubmitイベントを監視し、呼び出す`SupabaseManager.submitContactForm()`.&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;問題: これらのグローバル変数はフッターに注入されなくなりました。その`&amp;amp;lt;script src=&amp;quot;supabase-js&amp;quot;&amp;amp;gt;`削除されました。 コードは呼び出します。`supabase.createClient()`変数上に`supabase`存在しない。したがって :&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-none hljs&amp;quot;&amp;gt;console.error : &amp;#39;Supabase client library (supabase-js) is not loaded.&amp;#39;&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;データは保存されないだけでなく、提出コードは死んでいる。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_幽霊の二重提出&amp;quot;&amp;gt;幽霊の二重提出&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;事態をさらに悪化させるために、ある&amp;lt;strong&amp;gt;静かな競争&amp;lt;/strong&amp;gt;同じフォーム上の2つのハンドラー間で :&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;olist arabic&amp;quot;&amp;gt;
&amp;lt;ol class=&amp;quot;arabic&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;`contact.js`送信を聞き取り、Firebaseモックを呼び出す&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;code&amp;gt;script.js&amp;lt;/code&amp;gt;— 経由して`ContactFormHandler`— サブミットも聞いて、呼び出す`SupabaseManager`&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ol&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;両方は`event.preventDefault() + event.stopPropagation()&amp;lt;code&amp;gt;. ように`contact.js`最初にロードされます`footer.thyme&amp;lt;/code&amp;gt;, そのハンドラーは最初に接続されます。それが伝播をブロックします。`ContactFormHandler`決してトリガーされません。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;これはアクティブなバグではなく、むしろゾンビです。決して実行される機会のないコード。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div id=&amp;quot;diag-before&amp;quot; class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
skinparam backgroundColor #FEFEFE

title 初期状態 — お問い合わせフォーム
rectangle &amp;quot;contact.thyme\n(HTML Bootstrap, ハニーポット)&amp;quot; as FORM
rectangle &amp;quot;footer.thyme\n(Firebase SDK プレースホルダー構成)&amp;quot; as FOOT
rectangle &amp;quot;contact.js
(mock Firebase, 85% 成功)&amp;quot; as CONT
rectangle &amp;quot;script.js\n(SupabaseManager + ContactFormHandler, 死者)&amp;quot; as SCRIPT
rectangle &amp;quot;ユーザー&amp;quot; as USER

USER -&amp;amp;gt; FORM : Soumission du formulaire
FORM -&amp;amp;gt; CONT : submit event (attaché en premier)
CONT -&amp;amp;gt; CONT : preventDefault + stopPropagation
CONT -&amp;amp;gt; CONT : mock Promise (1.5s, aléatoire)
note right of CONT
  ⚠️ Aucune donnée stockée
end note

FORM ..&amp;amp;gt; SCRIPT : submit event (bloqué par stopPropagation)
note right of SCRIPT : ❌ Jamais déclenché
note right of SCRIPT : ❌ supabase-js non chargé

@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_なぜfirebaseをsupabaseの代わりに使うのか&amp;quot;&amp;gt;なぜFirebaseをSupabaseの代わりに使うのか？&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;移行の決定は文書化されています`AGENT.adoc`:&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;Firebaseは次の理由から選ばれています：無料プランが最適、ネイティブなFirestore、統合されたCloud Functions、Googleエコシステムに適合。既存のSupabase実装は「⚠️ 廃止済み」とマークされています。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;無料プランを超えると、アーキテクチャ上の理由があります。このサイトはGoogleのエコシステム内に存在します：ターゲットリポジトリは`cheroliv.github.io`, CNAMEはGitHub Pagesを指します。GradleビルドはJGitを介してGitHubにプッシュされます。サードパーティ製サービス（Supabase）ではなく、Googleサービス（Firebase）を追加すると、拡散領域が削減されます。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;Firestoreのネイティブモード（Datastoreモードではなく）は、私が頭に描いているドキュメント指向NoSQLのメンタルモデルにも近いです：コレクション、ドキュメント、型付きフィールド、サーバータイムスタンプ、組み込まれたセキュリティルール。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_フェーズ_1_firebase_プロジェクトを作成&amp;quot;&amp;gt;フェーズ 1 : Firebase プロジェクトを作成&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_初期化&amp;quot;&amp;gt;初期化&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;私のマシンに Firebase CLI がインストールされていないため、ウェブコンソールを使用しています：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;olist arabic&amp;quot;&amp;gt;
&amp;lt;ol class=&amp;quot;arabic&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;移動するhttps://console.firebase.google.com/[Firebase コンソール]&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;プロジェクトを作成`cheroliv-contact`(または既存のプロジェクトを再利用する)&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;Firestoreをネイティブモードで有効にする（Datastoreではない）&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;地域でデータベースを作成`eur3`(ヨーロッパ)&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ol&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;私たちのようにミニマリストな使い方（単一のコレクション、パブリックライティング）の場合、ネイティブモードが適切です。Datastoreの複雑なルールは必要ありません。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_firestoreセキュリティルール&amp;quot;&amp;gt;Firestoreセキュリティルール&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;フォームは公開されています — だれでもメッセージを送信できます。ただし、悪用を制限したいと思っています：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-javascript hljs&amp;quot; data-lang=&amp;quot;javascript&amp;quot;&amp;gt;rules_version = &amp;#39;2&amp;#39;;

service cloud.firestore {
  match /databases/{database}/documents {

    match /contact_messages/{messageId} {
      // Lecture : admin uniquement (authentifié)
      allow read: if request.auth != null;

      // Écriture : publique, mais limitée
      allow create: if request.auth == null
        &amp;amp;amp;&amp;amp;amp; request.resource.data.name is string
        &amp;amp;amp;&amp;amp;amp; request.resource.data.name.size() &amp;amp;gt;= 1
        &amp;amp;amp;&amp;amp;amp; request.resource.data.name.size() &amp;amp;lt;= 100
        &amp;amp;amp;&amp;amp;amp; request.resource.data.email is string
        &amp;amp;amp;&amp;amp;amp; request.resource.data.email.matches(&amp;#39;.*@.*\\..*&amp;#39;)
        &amp;amp;amp;&amp;amp;amp; request.resource.data.email.size() &amp;amp;lt;= 254
        &amp;amp;amp;&amp;amp;amp; request.resource.data.subject is string
        &amp;amp;amp;&amp;amp;amp; request.resource.data.subject.size() &amp;amp;gt;= 3
        &amp;amp;amp;&amp;amp;amp; request.resource.data.subject.size() &amp;amp;lt;= 200
        &amp;amp;amp;&amp;amp;amp; request.resource.data.message is string
        &amp;amp;amp;&amp;amp;amp; request.resource.data.message.size() &amp;amp;gt;= 10
        &amp;amp;amp;&amp;amp;amp; request.resource.data.message.size() &amp;amp;lt;= 5000
        &amp;amp;amp;&amp;amp;amp; request.resource.data.created_at == request.time
        &amp;amp;amp;&amp;amp;amp; request.resource.data.user_agent is string
        &amp;amp;amp;&amp;amp;amp; request.resource.data.user_agent.size() &amp;amp;lt;= 500;
    }
  }
}&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;主要ポイント：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;code&amp;gt;allow read&amp;lt;/code&amp;gt;— 認証済みのユーザーのみがメッセージを読むことができます（私、Firebase コンソール経由）&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;code&amp;gt;allow create&amp;lt;/code&amp;gt;— 誰でもドキュメントを作成できますが、フィールドのバリデーションがあります&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;サーバーサイドバリデーション：最小/最大サイズ、メール形式、&amp;lt;code&amp;gt;created_at`それに対応しなければならない`request.time&amp;lt;/code&amp;gt;(偽造防止)&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;`user_agent`トレーサビリティのために送信されます（クリティカルではありませんが、便利です）&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;これらのルールは単純なものよりも厳格です`allow write: if true;`. それらは攻撃者が巨大なペイロードや不正なフィールドを注入するのを防ぎます。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_フェーズ_2_提出のjavascriptを書き直す&amp;quot;&amp;gt;フェーズ 2: 提出のJavaScriptを書き直す&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;契約はシンプルです：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;olist arabic&amp;quot;&amp;gt;
&amp;lt;ol class=&amp;quot;arabic&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;フォームのデータを読み込む&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;honeypot (フィールド)を確認する`hp_name`— それが埋められているなら、それはボットで、何も送信せずに成功をシミュレートする)&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;呼ぶ`addDoc(window.&amp;lt;em&amp;gt;FIREBASE&amp;lt;/em&amp;gt;.collection(db, &amp;quot;contact_messages&amp;quot;), {&amp;amp;#8230;&amp;amp;#8203;})`&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;成功またはエラーを表示&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ol&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_依存関係_window_firebase&amp;quot;&amp;gt;依存関係 `window.&amp;lt;em&amp;gt;FIREBASE&amp;lt;/em&amp;gt;&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;中`footer.thyme`, モジュールスクリプトがFirebase SDKを初期化し、グローバルオブジェクトを公開します：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-html hljs&amp;quot; data-lang=&amp;quot;html&amp;quot;&amp;gt;&amp;amp;lt;script type=&amp;quot;module&amp;quot;&amp;amp;gt;
    import { initializeApp } from &amp;quot;https://www.gstatic.com/firebasejs/11.6.0/firebase-app.js&amp;quot;;
    import { getFirestore, collection, addDoc, serverTimestamp }
      from &amp;quot;https://www.gstatic.com/firebasejs/11.6.0/firebase-firestore.js&amp;quot;;

    const firebaseConfig = { /* valeurs réelles */ };
    const app = initializeApp(firebaseConfig);
    const db = getFirestore(app);

    window.__FIREBASE__ = { db, collection, addDoc, serverTimestamp };
&amp;amp;lt;/script&amp;amp;gt;&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;モジュールスクリプトは前に実行されます`DOMContentLoaded`, それで`window.&amp;lt;em&amp;gt;FIREBASE&amp;lt;/em&amp;gt;`はハンドラーのとき利用可能であることが保証されます`contact.js`トリガーされます。念のため、5秒間隔のポーリングを追加します。 CDNが遅い場合に備えて。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_新しい_contact_js&amp;quot;&amp;gt;新しい `contact.js&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-javascript hljs&amp;quot; data-lang=&amp;quot;javascript&amp;quot;&amp;gt;document.addEventListener(&amp;#39;DOMContentLoaded&amp;#39;, function () {
    &amp;#39;use strict&amp;#39;;

    const form = document.getElementById(&amp;#39;contact-form&amp;#39;);
    if (!form) return;

    const submitButton = form.querySelector(&amp;#39;button[type=&amp;quot;submit&amp;quot;]&amp;#39;);
    const successMessage = document.getElementById(&amp;#39;contact-success-message&amp;#39;);
    const errorMessage = document.getElementById(&amp;#39;contact-error-message&amp;#39;);

    // Éléments de validation
    const nameInput = form.querySelector(&amp;#39;input[name=&amp;quot;name&amp;quot;]&amp;#39;);
    const emailInput = form.querySelector(&amp;#39;input[name=&amp;quot;email&amp;quot;]&amp;#39;);
    const phoneInput = form.querySelector(&amp;#39;input[name=&amp;quot;phone&amp;quot;]&amp;#39;);
    const subjectInput = form.querySelector(&amp;#39;input[name=&amp;quot;subject&amp;quot;]&amp;#39;);
    const messageInput = form.querySelector(&amp;#39;textarea[name=&amp;quot;message&amp;quot;]&amp;#39;);
    const honeypotInput = form.querySelector(&amp;#39;input[name=&amp;quot;hp_name&amp;quot;]&amp;#39;);

    /**
     * Attend que window.__FIREBASE__ soit disponible.
     * Timeout de 5 secondes — si le CDN Firebase est lent, on abandonne.
     */
    function waitForFirebase(timeoutMs = 5000) {
        return new Promise((resolve, reject) =&amp;amp;gt; {
            if (window.__FIREBASE__) {
                resolve(window.__FIREBASE__);
                return;
            }
            const start = Date.now();
            const interval = setInterval(() =&amp;amp;gt; {
                if (window.__FIREBASE__) {
                    clearInterval(interval);
                    resolve(window.__FIREBASE__);
                } else if (Date.now() - start &amp;amp;gt; timeoutMs) {
                    clearInterval(interval);
                    reject(new Error(&amp;#39;Firebase SDK non disponible après timeout&amp;#39;));
                }
            }, 100);
        });
    }

    // --- Validation (identique à l&amp;#39;existant) ---
    function validateForm() {
        nameInput.setCustomValidity(&amp;#39;&amp;#39;);
        emailInput.setCustomValidity(&amp;#39;&amp;#39;);
        if (phoneInput) phoneInput.setCustomValidity(&amp;#39;&amp;#39;);
        subjectInput.setCustomValidity(&amp;#39;&amp;#39;);
        messageInput.setCustomValidity(&amp;#39;&amp;#39;);

        if (nameInput.value.trim().length &amp;amp;lt; 1) {
            nameInput.setCustomValidity(&amp;#39;Veuillez saisir votre nom.&amp;#39;);
        }
        const emailPattern = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
        if (!emailPattern.test(emailInput.value.trim())) {
            emailInput.setCustomValidity(&amp;#39;Veuillez saisir une adresse email valide.&amp;#39;);
        }
        if (phoneInput &amp;amp;amp;&amp;amp;amp; phoneInput.value.trim() !== &amp;#39;&amp;#39;) {
            const phonePattern = /^\d{10,15}$/;
            if (!phonePattern.test(phoneInput.value.trim())) {
                phoneInput.setCustomValidity(&amp;#39;Veuillez saisir un numéro valide (10 à 15 chiffres).&amp;#39;);
            }
        }
        if (subjectInput.value.trim().length &amp;amp;lt; 3) {
            subjectInput.setCustomValidity(&amp;#39;Veuillez saisir un sujet (3 caractères minimum).&amp;#39;);
        }
        if (messageInput.value.trim().length &amp;amp;lt; 10) {
            messageInput.setCustomValidity(&amp;#39;Veuillez saisir un message (10 caractères minimum).&amp;#39;);
        }

        form.classList.add(&amp;#39;was-validated&amp;#39;);
        return form.checkValidity();
    }

    // --- Handler de soumission ---
    form.addEventListener(&amp;#39;submit&amp;#39;, async function (event) {
        event.preventDefault();
        event.stopPropagation();

        if (!validateForm()) return;

        // Honeypot : si rempli, simuler un succès sans rien envoyer
        if (honeypotInput &amp;amp;amp;&amp;amp;amp; honeypotInput.value.trim() !== &amp;#39;&amp;#39;) {
            successMessage.style.display = &amp;#39;block&amp;#39;;
            form.reset();
            form.classList.remove(&amp;#39;was-validated&amp;#39;);
            return;
        }

        // UI : état d&amp;#39;envoi
        submitButton.disabled = true;
        submitButton.innerHTML = `
            &amp;amp;lt;span class=&amp;quot;spinner-border spinner-border-sm&amp;quot; role=&amp;quot;status&amp;quot; aria-hidden=&amp;quot;true&amp;quot;&amp;amp;gt;&amp;amp;lt;/span&amp;amp;gt;
            Envoi en cours...
        `;
        successMessage.style.display = &amp;#39;none&amp;#39;;
        errorMessage.style.display = &amp;#39;none&amp;#39;;

        try {
            const fb = await waitForFirebase();
            const messagesCollection = fb.collection(fb.db, &amp;#39;contact_messages&amp;#39;);

            await fb.addDoc(messagesCollection, {
                name: nameInput.value.trim(),
                email: emailInput.value.trim(),
                phone: phoneInput ? phoneInput.value.trim() : &amp;#39;&amp;#39;,
                subject: subjectInput.value.trim(),
                message: messageInput.value.trim(),
                created_at: fb.serverTimestamp(),
                user_agent: navigator.userAgent.substring(0, 500)
            });

            successMessage.style.display = &amp;#39;block&amp;#39;;
            form.reset();
            form.classList.remove(&amp;#39;was-validated&amp;#39;);

        } catch (error) {
            console.error(&amp;#39;Erreur Firestore:&amp;#39;, error);
            errorMessage.style.display = &amp;#39;block&amp;#39;;

        } finally {
            submitButton.disabled = false;
            submitButton.innerHTML = `
                &amp;amp;lt;i class=&amp;quot;bi bi-send me-2&amp;quot;&amp;amp;gt;&amp;amp;lt;/i&amp;amp;gt;
                Envoyer le Message
            `;
        }
    }, false);
});&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;モックとの変更点:&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;code&amp;gt;waitForFirebase()&amp;lt;/code&amp;gt;— タイムアウト付きポーリング、CDNが遅くても堅牢&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;code&amp;gt;honeypot&amp;lt;/code&amp;gt;— もし隠しフィールドの場合`hp_name`満たされており、Firestoreの成功を偽装している。ボットは成功したと思っているが、何も保存されていない。&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;code&amp;gt;addDoc(collection, {&amp;amp;#8230;&amp;amp;#8203;})&amp;lt;/code&amp;gt;— 本当のFirestore呼び出しと`serverTimestamp()` et &amp;lt;code&amp;gt;user_agent&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;エラー処理と`try/catch`非同期&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;掃除の`finally`(ボタンの復元)&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;admonitionblock note&amp;quot;&amp;gt;
&amp;lt;table&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;icon&amp;quot;&amp;gt;
&amp;lt;i class=&amp;quot;fa icon-note&amp;quot; title=&amp;quot;Note&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;
&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;なぜ`user_agent`? オプションですが、診断に役立ちます。変なメッセージが届いたとき、それがデスクトップブラウザ、モバイル、またはcurlスクリプトから来ているかを知ると、振り分けに役立ちます。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/table&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_phase_3_supabaseのデッドコードをクリーンアップ&amp;quot;&amp;gt;Phase 3 : Supabaseのデッドコードをクリーンアップ&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;`script.js`250行のデッドコードが含まれています：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;code&amp;gt;SupabaseManager&amp;lt;/code&amp;gt;(417-481行) — 65行&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;code&amp;gt;ContactFormHandler&amp;lt;/code&amp;gt;(490-551行) — 62行&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;初期化ブロック (行 645-654) — 10 行&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;合計：約140行を削除&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;ブロック`DOMContentLoaded`作る`SupabaseManager`それから一つ`ContactFormHandler`フォームに付随して。上記のように説明した通り、このコードは決して実行されません(ブロックされている`contact.js`), たとえ実行されたとしても、失敗します（Supabase SDKがロードされていません）。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;�削除します:&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;olist arabic&amp;quot;&amp;gt;
&amp;lt;ol class=&amp;quot;arabic&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;クラス`SupabaseManager`&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;クラス`ContactFormHandler`&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;初期化ブロックの中`DOMContentLoaded`(645-654行)&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ol&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;Le reste de &amp;lt;code&amp;gt;script.js`は無傷です：`ThemeManager&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ScrollToTopButton&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;MobileMenuManager&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;SmoothScrollWithOffset&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;NavbarHeightUpdater&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;DynamicNavbarBreakpoint&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;CodeBlockManager&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;TooltipManager&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;PhoneInputManager&amp;lt;/code&amp;gt;.&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_フェーズ_4_フッターを設定する&amp;quot;&amp;gt;フェーズ 4: フッターを設定する&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;`footer.thyme`既にFirebaseのボイラープレートがありますが、プレースホルダー値のため、私は置き換えます：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-javascript hljs&amp;quot; data-lang=&amp;quot;javascript&amp;quot;&amp;gt;const firebaseConfig = {
    apiKey: &amp;quot;REMPLACER_PAR_VOTRE_API_KEY&amp;quot;,
    authDomain: &amp;quot;REMPLACER_PAR_VOTRE_AUTH_DOMAIN&amp;quot;,
    projectId: &amp;quot;REMPLACER_PAR_VOTRE_PROJECT_ID&amp;quot;,
    storageBucket: &amp;quot;REMPLACER_PAR_VOTRE_STORAGE_BUCKET&amp;quot;,
    messagingSenderId: &amp;quot;REMPLACER_PAR_VOTRE_SENDER_ID&amp;quot;,
    appId: &amp;quot;REMPLACER_PAR_VOTRE_APP_ID&amp;quot;
};&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;取得された実際の値から&amp;lt;strong&amp;gt;プロジェクト設定 &amp;amp;gt; 一般 &amp;amp;gt; あなたのアプリ &amp;amp;gt; Webアプリ&amp;lt;/strong&amp;gt;Firebase コンソール内で。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;値は敏感です`apiKey`Firebaseでは設計上公開されていますが、私はプレーンテキストでコミットするのを好みません)。私はそれらを保存しています`site.yml`(既に 中に`.gitignore`) とプラグイン`bakery`ビルド側に追加するロジックを使って、テンプレートにそれらを注入します。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;今のところ、それをそのまま中に入れています`footer.thyme`— ビルド`./gradlew serve`それらはローカルで読み込まれます。デプロイ時に、インジェクションを移行します。`site.yml`または Gradle変数へ&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;admonitionblock warning&amp;quot;&amp;gt;
&amp;lt;table&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;icon&amp;quot;&amp;gt;
&amp;lt;i class=&amp;quot;fa icon-warning&amp;quot; title=&amp;quot;Warning&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;
&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;L&amp;#39;`apiKey`Firebaseは&amp;lt;strong&amp;gt;ない&amp;lt;/strong&amp;gt;秘密です。設計上公開されています。あなたのデータを保護するものは&amp;lt;strong&amp;gt;Firestore のセキュリティ ルール&amp;lt;/strong&amp;gt;, APIキーではありません。 これに入れないで`.env`サーバーサイドで読み込まれ — ブラウザに公開することを意図しています。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/table&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_フェーズ_5_最終アーキテクチャ&amp;quot;&amp;gt;フェーズ 5 : 最終アーキテクチャ&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div id=&amp;quot;diag-after&amp;quot; class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
skinparam backgroundColor #FEFEFE

title 最終アーキテクチャ — Firebaseお問い合わせフォーム
actor Utilisateur as USER

package &amp;quot;ブラウザ&amp;quot; #E8F5E9 {
  rectangle &amp;quot;contact.thyme\n(HTML, honeypot)&amp;quot; as FORM
  rectangle &amp;quot;contact.js\n(validation + Firestore)&amp;quot; as CONT
  rectangle &amp;quot;footer.thyme\n(Firebase SDK 初期化)&amp;quot; as FOOT
}

cloud &amp;quot;ファイアベース&amp;quot; #BBDEFB {
  rectangle &amp;quot;Firestore\n(連絡メッセージ)&amp;quot; as FS
}

FORM --&amp;amp;gt; CONT : submit event
CONT --&amp;amp;gt; FOOT : window.__FIREBASE__.addDoc()
FOOT --&amp;amp;gt; FS : Insert document\n(règles de sécurité validées)

note right of FS
  Firestore Rules :
  - create: public, validé
  - read: auth uniquement
end note

@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_この移行がドッグフーディングについて何を言っているか&amp;quot;&amp;gt;この移行がドッグフーディングについて何を言っているか&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;このサイトは、私の独自のGradleプラグインで生成されます。&amp;lt;code&amp;gt;bakery&amp;lt;/code&amp;gt;. コンタクトフォームはサイト内に存在します。 Supabase → Firebase への移行はドキュメント化されています。&amp;lt;code&amp;gt;AGENT.adoc&amp;lt;/code&amp;gt;, バックログで議論され、経由でテストされています`./gradlew serve`, そして、それはブログ記事を生成します（あなたが今読んでいるものです）。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;これは純粋なドッグフーディングです。サイトはプラグインの製品であり、プラグインは開発者の製品であり、開発者はサイト自身でプロセスを文書化しています。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;一周回った。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;何ヶ月もモックを抱え続けていたこと（フォームが黙って嘘をつく、まるまる一日のセッションが続いたこと）が、私にあることに気づかせた。個人の静的サイトのバックログは決して「終わる」ものではない。常に優先されるユーザーストーリーがあり、常にドラフトの記事があり、常にテンプレート内にコメントアウトされたセクションがある。規律とは、すべてを終わらせることではなく、ユーザーに見えるものを終わらせることである。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;�壊れたお問い合わせフォームは、フォームがないよりも悪い。それは守られなかった約束だ。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_変更のまとめ&amp;quot;&amp;gt;変更のまとめ&amp;lt;/h3&amp;gt;
&amp;lt;table class=&amp;quot;tableblock frame-all grid-all stretch&amp;quot;&amp;gt;
&amp;lt;colgroup&amp;gt;
&amp;lt;col style=&amp;quot;width: 6.6666%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 6.6666%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 6.6666%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 6.6666%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 6.6666%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 6.6666%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 6.6666%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 6.6666%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 6.6666%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 6.6666%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 6.6666%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 6.6666%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 6.6666%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 6.6666%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 6.6676%;&amp;quot;&amp;gt;
&amp;lt;/colgroup&amp;gt;
&amp;lt;tbody&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;ファイル&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;変更&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;インパクト&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;code&amp;gt;blog/2026/0113_*.adoc&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;記事の作成&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;ドキュメンテーション&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;code&amp;gt;assets/js/contact.js&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;書き換え(モック→実際のFirestore)&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;機能的&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;code&amp;gt;assets/js/script.js&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;SupabaseManager + ContactFormHandler + init bloc の削除&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;�掃除&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;code&amp;gt;templates/footer.thyme&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;設定プレースホルダーの置換 → 実際の値&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;構成&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/tbody&amp;gt;
&amp;lt;/table&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_次のステップ_バックログ&amp;quot;&amp;gt;次のステップ (バックログ)&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;通知メール&amp;lt;/strong&amp;gt;: 一つのクラウドファンクション`onCreate`の上に`contact_messages`SendGrid を介してメールを送信します。フォームはデータを保存しますが、私は通知を受けません。優先度は中 — メッセージは Firebase コンソールで表示されます。&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;クライアント側レート制限&amp;lt;/strong&amp;gt;: localStorageにタイムスタンプを追加して、連続した複数の送信を防ぎます。ハニーポットは初心者ボットをブロックし、レートリミッターはやや賢いボットをブロックします。&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;テスト&amp;lt;/strong&amp;gt;: フォームを送信し、ドキュメントがFirestoreに表示されることを確認するPlaywrightのテスト。現在、手動でテストしています via`./gradlew serve`。&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_参考文献&amp;quot;&amp;gt;参考文献&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;https://firebase.google.com/docs/firestore/security/get-started&amp;quot;&amp;gt;Firestore セキュリティルール ドキュメント&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;https://firebase.google.com/docs/firestore/manage-data/add-data#add_a_document&amp;quot;&amp;gt;Firestore addDoc ドキュメント — Web v9 モジュール&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;/blog/2026/0108_gouvernance_agent_opencode_eager_lazy_post.html&amp;quot;&amp;gt;エージェントガバナンスシリーズ — 第1部: Eager/Lazy&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;/blog/2026/0110_mecanisme_backup_contexte_agent_post.html&amp;quot;&amp;gt;エージェントガバナンスシリーズ — 第2部: ホット/ウォーム/コールド&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;/blog/2026/0111_audit_contexte_agent_post.html&amp;quot;&amp;gt;エージェントガバナンスシリーズ — パート3：監査&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;</description>
        </item><item>
            <title>DeepSeek-V4-Pro, Kimi K2.6、GLM-5.1：3つのLLMがバイブコーディングロングコンテキストに挑戦</title>
            <link >https://cheroliv.com/blog/2026/0112_comparaison_kimi_glm_deepseek_long_contexte_plugin_gradle_opencode_post.html</link>
            <pubDate>Tue, 28 Apr 2026 00:00:00 +0000</pubDate>
            <guid isPermaLink="false">blog/2026/0112_comparaison_kimi_glm_deepseek_long_contexte_plugin_gradle_opencode_post.html</guid>
            <description>&amp;lt;div id=&amp;quot;toc&amp;quot; class=&amp;quot;toc&amp;quot;&amp;gt;
&amp;lt;div id=&amp;quot;toctitle&amp;quot;&amp;gt;Table des matières&amp;lt;/div&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel1&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_コンテキストテストベンチではなく建設現場&amp;quot;&amp;gt;コンテキスト：テストベンチではなく、建設現場&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_私のテスト環境&amp;quot;&amp;gt;私のテスト環境&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_評価グリッド&amp;quot;&amp;gt;評価グリッド&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_round_1_kimi_k2_6偽のスタート&amp;quot;&amp;gt;Round 1: Kimi K2.6—偽のスタート&amp;lt;/a&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel2&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_第9回好転&amp;quot;&amp;gt;第9回：好転&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_セッション_10_静かな難破&amp;quot;&amp;gt;セッション 10 : 静かな難破&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_ラウンド_2_glm_5_1_名誉の戦士&amp;quot;&amp;gt;ラウンド 2 : GLM-5.1 — 名誉の戦士&amp;lt;/a&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel2&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_アーキテクチャdsa対純粋mla&amp;quot;&amp;gt;アーキテクチャ：DSA対純粋MLA&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_セッション11_13_堅実だがフラストレーションがたまる&amp;quot;&amp;gt;セッション11-13: 堅実だがフラストレーションがたまる&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_round_3_deepseek_v4_pro_戦争の機械&amp;quot;&amp;gt;Round 3 : DeepSeek-V4-Pro — 戦争の機械&amp;lt;/a&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel2&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_アーキテクチャ_csa_hca_ダブルネット&amp;quot;&amp;gt;アーキテクチャ: CSA + HCA, ダブルネット&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_セッション1_8安堵&amp;quot;&amp;gt;セッション1-8：安堵&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_決定的なテスト100kトークンのリファクタリング&amp;quot;&amp;gt;決定的なテスト：100Kトークンのリファクタリング&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_フェイストゥフェイス_比較メトリクス&amp;quot;&amp;gt;フェイス・トゥ・フェイス : 比較メトリクス&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_なぜdeepseek_v4_proはソフトウェア開発で勝つのか&amp;quot;&amp;gt;なぜDeepSeek-V4-Proはソフトウェア開発で勝つのか&amp;lt;/a&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel2&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_1_csahca_アーキテクチャはコードに最適化されています&amp;quot;&amp;gt;1. CSA+HCA アーキテクチャはコードに最適化されています&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_2_eagerコンテキストは彼彼女の快適ゾーン&amp;quot;&amp;gt;2. EAGERコンテキストは彼/彼女の快適ゾーン&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_3_品質遅延比はフローに最適だ&amp;quot;&amp;gt;3. 品質/遅延比はフローに最適だ&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_学んだ教訓_vibe_codingのためのllmの選び方&amp;quot;&amp;gt;学んだ教訓 : Vibe CodingのためのLLMの選び方&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_エージェントガバナンスはこの中でどうなの&amp;quot;&amp;gt;エージェントガバナンスはこの中でどうなの？&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_技術的な情報源&amp;quot;&amp;gt;技術的な情報源&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_結論職人の選択&amp;quot;&amp;gt;結論：職人の選択&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div id=&amp;quot;preamble&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;読了時間 : 18 minutes&amp;lt;/div&amp;gt;
&amp;lt;p&amp;gt;LLMの戦いは開発者のターミナルでも行われます。学術的な無意味なベンチマークではなく。実際の現場では：30,000トークンのプロンプト、AsciiDocで書かれたエージェントガバナンス、デバッグが必要なGradle Kotlin DSLプラグイン、そして3週間続くセッションが連続してあります。あなたのためにDeepSeek-V4-Pro、Kimi K2.6、GLM-5.1をテストしました。ここに結論があり、技術的証拠によって裏付けられています。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;dlist&amp;quot;&amp;gt;
&amp;lt;dl&amp;gt;
&amp;lt;dt class=&amp;quot;hdlist1&amp;quot;&amp;gt;トック&amp;lt;/dt&amp;gt;
&amp;lt;dd&amp;gt;
&amp;lt;p&amp;gt;&amp;amp;lt;/think&amp;amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/dd&amp;gt;
&amp;lt;/dl&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_コンテキストテストベンチではなく建設現場&amp;quot;&amp;gt;コンテキスト：テストベンチではなく、建設現場&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;3週間前、私はそれに取り組んでいた`codebase-gradle`私のメタビルドシステムは、4つのプロジェクト（PlantUML用READMEジェネレーター、AsciiDocスライドビルダー、静的JBakeサイト、LLMチャットボット）のYAML設定を一元管理します。Opencodeエージェントは、AsciiDocで記述された私のエージェントファイルメソッドに従い、各セッション開始時に約30KトークンのEAGERコンテキストをロードしていました—絶対的ルール、バックログ、過去10セッションの履歴。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;それがこの場所で、私は三つのモデルと対峙した：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;Kimi K2.6&amp;lt;/strong&amp;gt;(Moonshot AI, 1T パラメータ / 32B アクティベート済み, 256K コンテキスト最大, MLA) - &amp;lt;strong&amp;gt;GLM-5.1&amp;lt;/strong&amp;gt;(Zhipu AI/Tsinghua, 744B params / DSA, 200K 最大コンテキスト) - &amp;lt;strong&amp;gt;DeepSeek-V4-Pro&amp;lt;/strong&amp;gt;(DeepSeek, 1.6T パラメータ / 49B アクティベート済み, 1M コンテキスト 最大, CSA+HCA)&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;すべてクラウドサーバーの Ollama を介して提供され、すべて思考モード（考察フェーズが有効）で動作します。課題は、正しいコードを生成し、長時間のセッションで一貫性を保ち、コンテキストが 80K トークンを超えたときに幻覚を起こさないことです。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_私のテスト環境&amp;quot;&amp;gt;私のテスト環境&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div id=&amp;quot;diag-dev-env&amp;quot; class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
skinparam backgroundColor #FEFEFE
skinparam defaultTextAlignment center
skinparam wrapWidth 220

title テスト環境 — Opencode セッション × 3 LLMs
left to right direction

package &amp;quot;🖥️開発者用ターミナル&amp;quot; #E8F5E9 {
  rectangle &amp;quot;AGENT.adoc\n(ルール, バックログ)&amp;quot; as AG
  rectangle &amp;quot;PROMPT_REPRISE\n(ミッション)&amp;quot; as PR
  rectangle &amp;quot;INDEX.adoc
(ロードマップ)&amp;quot; as IDX
}

package &amp;quot;�☁️ Ollama クラウド&amp;quot; #BBDEFB {
  rectangle &amp;quot;DeepSeek-V4-Pro\n1.6T / CSA+HCA&amp;quot; as DV4
  rectangle &amp;quot;Kimi K2.6
1T / MLA&amp;quot; as KIMI
  rectangle &amp;quot;GLM-5.1\n744B / MLA+DSA&amp;quot; as GLMG
}

package &amp;quot;�⚙️ コードベース Gradle&amp;quot; #FFF9C4 {
  folder &amp;quot;buildSrc/&amp;quot; {
    file &amp;quot;codebase.kt&amp;quot;
    file &amp;quot;readme.kt&amp;quot;
    file &amp;quot;site.kt&amp;quot;
    file &amp;quot;slider.kt&amp;quot;
    file &amp;quot;snapshot.kt&amp;quot;
  }
  file &amp;quot;build.gradle.kts
(947行)&amp;quot;
  file &amp;quot;embeds.yml&amp;quot;
}

AG --&amp;amp;gt; DV4 : Sessions 1-8 ✅
AG --&amp;amp;gt; KIMI : Sessions 9-10 ⚠️
AG --&amp;amp;gt; GLMG : Sessions 11-13 ⚠️

DV4 --&amp;amp;gt; &amp;quot;コードベース&amp;quot; : &amp;quot;TDD, リファクタリング,\nスナップショット&amp;quot;
KIMI --&amp;amp;gt; &amp;quot;コードベース&amp;quot; : &amp;quot;劣化
60Kトークンから&amp;quot;

note bottom of GLMG
  Meilleur que Kimi
  mais latence +
  DSA moins robuste
  que CSA+HCA
end note

@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;各セッションは約30KトークンのEAGERコンテキストで開始されました：&amp;lt;code&amp;gt;AGENT.adoc&amp;lt;/code&amp;gt;(287 行)&amp;lt;code&amp;gt;PROMPT_REPRISE.adoc&amp;lt;/code&amp;gt;(51 行),&amp;lt;code&amp;gt;.agents/INDEX.adoc&amp;lt;/code&amp;gt;(218行),&amp;lt;code&amp;gt;LAZY_EAGER_ESSENTIALS.adoc&amp;lt;/code&amp;gt;(50 行). コンテキストはやり取りとともに急速に膨らみ — 10メッセージの典型的なセッションでは累積プロンプトに15-20K トークンが追加されました。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_評価グリッド&amp;quot;&amp;gt;評価グリッド&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;私は各モデルを、AI支援型ソフトウェア開発にとって重要な4つの軸で評価しました：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;table class=&amp;quot;tableblock frame-all grid-all stretch&amp;quot;&amp;gt;
&amp;lt;colgroup&amp;gt;
&amp;lt;col style=&amp;quot;width: 10%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 10%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 10%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 10%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 10%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 10%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 10%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 10%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 10%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 10%;&amp;quot;&amp;gt;
&amp;lt;/colgroup&amp;gt;
&amp;lt;tbody&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;�軸&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;具体的な基準&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;長い文脈の一貫性&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;エージェントは40メッセージ前に決められた規約を覚えていますか。&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;生成されたコードの品質&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;コードは最初の試みでコンパイルできますか？ 既存のパターンに従っていますか？&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;建築的推論&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;エージェントは、私が再説明しなくてもモジュール間の関係を理解していますか？&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;幻覚への耐性&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;エージェントは何トークンから、存在しないAPIやクラスをでっち上げ始めるのか？&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/tbody&amp;gt;
&amp;lt;/table&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;そして自家製の合成メトリクス : その&amp;lt;strong&amp;gt;回復係数&amp;lt;/strong&amp;gt;(彼とコードを書くよりもエージェントを修正する時間がどれくらいか).&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_round_1_kimi_k2_6偽のスタート&amp;quot;&amp;gt;Round 1: Kimi K2.6—偽のスタート&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;Kimi K2.6は私の最初の選択でした。SWE-Bench Verified (80.2)およびTerminal-Bench 2.0 (66.7)でのベンチマークは優れています。MLAアーキテクチャは長いシーケンスに対して良い効率性を約束します。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_第9回好転&amp;quot;&amp;gt;第9回：好転&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;Kimi との最初のセッション。タスク：メソッドを実装する`resolveActiveKey()&amp;lt;code&amp;gt;中に`codebase.kt&amp;lt;/code&amp;gt;— APIキー解決関数にCLIフォールバック付き。コンテキストは30Kトークンで、Kimiは素早く推論し、キーの有効期限管理を含むクリーンなコードを生成します。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-kotlin hljs&amp;quot; data-lang=&amp;quot;kotlin&amp;quot;&amp;gt;fun resolveActiveKey(
    cfg: CodebaseConfiguration,
    logger: Logger,
    cliProvider: String? = null,
    cliAccount: String? = null,
    cliKey: String? = null
): NamedApiKey? {
    // Résolution provider → compte → clé avec CLI override
    // Kimi a parfaitement compris la chaîne de priorité
}&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;コードはコンパイルされます。7つのテストケースがパスします。私は楽観的です。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_セッション_10_静かな難破&amp;quot;&amp;gt;セッション 10 : 静かな難破&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;2番目のセッション。コンテキストは交換とともに~90Kトークンに増加します。Kimiに、書き込む前にシークレットを匿名化するAsciiDocスナップショットメカニズムを追加するよう依頼します。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;ここでそれが脱線する。Kimiは存在しないクラスを考案し始める。彼は私に提案する`AnonymizedObjectMapper`— 架空のクラス。 彼は混同する`ReadmeYmlAnonymizer` et &amp;lt;code&amp;gt;CodebaseYmlAnonymizer&amp;lt;/code&amp;gt;. 彼は私にインポートすることを提案します。&amp;lt;code&amp;gt;com.fasterxml.jackson.anonymize.*&amp;lt;/code&amp;gt;— 存在したことのないパッケージ。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;もっと悪いことに：彼の思考の段階で、彼が誤った前提に基づいて論理を構築しているのがわかります。彼は「思い出す」が`GitConfig`畑を持っている`anonymizedToken`— いいえ、それは`resolvedToken()&amp;lt;code&amp;gt;. 彼は…に帰する`SiteYmlAnonymizer`方法`maskSupabaseCredentials()&amp;lt;/code&amp;gt;— 存在しない。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;em&amp;gt;&amp;lt;em&amp;gt;_ それはバグではなかった。それは一貫性の段階的な崩壊だった。まるで、コンテキストに追加される各トークンが、最初の30,000の記憶を少しずつ薄めていくかのように。 &amp;lt;/em&amp;gt;_&amp;lt;/em&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;Kimiを2セッション後に停止する。診断は明らかだ：MLAはKVキャッシュをうまく圧縮するが、細粒度のスパース選択メカニズムがないと、注意は60Kトークン以上で機械的に薄まる。各トークンは「見る」遠いコンテキストをますますうまくできなくなり — そして、ノイズで穴を埋め始める。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_ラウンド_2_glm_5_1_名誉の戦士&amp;quot;&amp;gt;ラウンド 2 : GLM-5.1 — 名誉の戦士&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;GLM-5.1 は異なるアーキテクチャで登場します：ベースモデルに MLA、その後 &amp;lt;strong&amp;gt;continued pre-training&amp;lt;/strong&amp;gt; を DSA (DeepSeek Sparse Attention) で行います — これは軽量なインデクサーで、動的に全履歴から関連性の高いトップ 2048 トークンを選択します。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_アーキテクチャdsa対純粋mla&amp;quot;&amp;gt;アーキテクチャ：DSA対純粋MLA&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;違いは根本的です。Kimiが歴史を単一の潜在空間に圧縮し（その結果、関連情報を識別する能力を徐々に失うのに対し）、GLMは事後トレーニングのインデクサを接ぎ木し、明示的なスパース選択を行います。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div id=&amp;quot;diag-mla-vs-dsa&amp;quot; class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
skinparam backgroundColor #FEFEFE
skinparam defaultTextAlignment center

title 注意アーキテクチャ — MLA対MLA+DSA
left to right direction

rectangle &amp;quot;**Kimi K2.6 — MLA 純粋**&amp;quot; as MLA #FFCDD2 {
  rectangle &amp;quot;KV Cache
完全&amp;quot; as KV1
  rectangle &amp;quot;�圧縮
潜在&amp;quot; as CL1
  rectangle &amp;quot;デコード
潜在空間で&amp;quot; as DL1
  KV1 --&amp;amp;gt; CL1
  CL1 --&amp;amp;gt; DL1
  note bottom of DL1
    ⚠️ Au-delà de 60K tokens :
    perte de discrimination
  end note
}

rectangle &amp;quot;GLM-5.1 — MLA + DSA&amp;quot; as DSA #C8E6C9 {
  rectangle &amp;quot;KV Cache
完全&amp;quot; as KV2
  rectangle &amp;quot;�潜在圧縮 (MLA)&amp;quot; as CL2
  rectangle &amp;quot;軽量インデクサー\n(DSA, top-k=2048)&amp;quot; as IL
  rectangle &amp;quot;デコード
選択されたトークン上で&amp;quot; as DL2
  KV2 --&amp;amp;gt; CL2
  CL2 --&amp;amp;gt; IL
  IL --&amp;amp;gt; DL2
  note bottom of DL2
    ✅ &amp;quot;構築による無損失&amp;quot;
    Sélection explicite
    des tokens pertinents
  end note
}

MLA --&amp;amp;gt; DSA : &amp;quot;ゲイン : スパース選択
希釈を避ける&amp;quot;

@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;技術レポートは明示的に述べている：DSAは &amp;lt;em&amp;gt;&amp;quot;lossless by construction&amp;quot;&amp;lt;/em&amp;gt;  — それに対して、SWA（パターンサーチ）、Gated DeltaNet、SimpleGDNなどの代替手段はRULER@128Kで最大5.69ポイント損失する。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_セッション11_13_堅実だがフラストレーションがたまる&amp;quot;&amp;gt;セッション11-13: 堅実だがフラストレーションがたまる&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;GLM-5.1は距離を保つのが得意です。セッション11（約60Kトークン）では、一貫性を保っています。それは&amp;amp;#8230;&amp;amp;#8203;を生成します。`SnapshotManager`機能的で、4つの匿名化ツールの管理が正しく行われている。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;しかし、遅延は問題です。DSAの思考フェーズは純粋なMLAよりも重く — インデクサは各ステップで履歴を再スキャンする必要があります。Kimiで8秒かかった回答が、GLMでは15秒になります。30メッセージのセッションでは、これがはっきりと感じられます。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;そしてそこに微妙な誤りがあります。GLMはKimiのように妄想をしないが、*命名*の間違いを犯す。彼は呼ぶ`toAnonymizedYaml()&amp;lt;code&amp;gt;呼び出すべきメソッド`anonymize()&amp;lt;/code&amp;gt;. 彼は逆転する`loadReadmeConfiguration()` et &amp;lt;code&amp;gt;loadCodebaseConfiguration()`の 中`renderFileSection()&amp;lt;/code&amp;gt;. これは幻覚ではなく、表面的な混同です — ただし本番環境では、表面的な混同がビルドを壊すことがあります。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;GLMと3回のセッションを行った。それはKimiよりも間違いなく優れている。しかし、命名の詳細に関する手動修正を3回行うのは疲れる。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_round_3_deepseek_v4_pro_戦争の機械&amp;quot;&amp;gt;Round 3 : DeepSeek-V4-Pro — 戦争の機械&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;DeepSeek-V4-Pro は、3 つの中で最も野心的なアーキテクチャを備えています：補完的な 2 つの注意機構を組み合わせたハイブリッド システムです。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_アーキテクチャ_csa_hca_ダブルネット&amp;quot;&amp;gt;アーキテクチャ: CSA + HCA, ダブルネット&amp;lt;/h3&amp;gt;
&amp;lt;div id=&amp;quot;diag-csa-hca&amp;quot; class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
skinparam backgroundColor #FEFEFE
skinparam defaultTextAlignment center
skinparam wrapWidth 180

title DeepSeek-V4-Pro — ハイブリッドアーキテクチャ CSA + HCA
left to right direction

rectangle &amp;quot;KV Cache
1M トークン&amp;quot; as KV #E3F2FD

rectangle &amp;quot;CSA
圧縮スパースアテンション&amp;quot; as CSA #C8E6C9 {
  rectangle &amp;quot;圧縮
m トークン → 1&amp;quot; as CC
  rectangle &amp;quot;スパース アテンション
(DSA, トップk)&amp;quot; as SA
  CC --&amp;amp;gt; SA

  note bottom of SA
    Attention locale fine
    + sélection sparse
  end note
}

rectangle &amp;quot;HCA
大幅に圧縮された注意&amp;quot; as HCA #BBDEFB {
  rectangle &amp;quot;極限の圧縮
m&amp;#39; &amp;amp;gt;&amp;amp;gt; m → 1&amp;quot; as ECC
  rectangle &amp;quot;密な注意\n残存&amp;quot; as EDA
  ECC --&amp;amp;gt; EDA

  note bottom of EDA
    Contexte global
    + connexions longue distance
  end note
}

rectangle &amp;quot;ハイブリッド
フュージョン&amp;quot; as FUSION #FFF9C4
rectangle &amp;quot;復号
コヒーレント&amp;quot; as DEC #FFE0B2

KV --&amp;amp;gt; CSA : Précision locale
KV --&amp;amp;gt; HCA : Vision globale

CSA --&amp;amp;gt; FUSION
HCA --&amp;amp;gt; FUSION
FUSION --&amp;amp;gt; DEC

@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;2レベルの圧縮、2段階の注意の粒度：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;CSA&amp;lt;/strong&amp;gt;KVキャッシュを圧縮するごとに`m`tokens、続いてDeepSeek Sparse Attention（スパースアテンション）を適用します — 圧縮された入力のうちトップkのみが参照されます。正確、局所的、効率的。 - &amp;lt;strong&amp;gt;HCA&amp;lt;/strong&amp;gt;: 極端な圧縮 (因子`m&amp;#39;`ずっと大きい`m`), しかし、圧縮された残渣に対して密な注意を払い — 二次的な爆発を引き起こさずにグローバルな接続を維持する。&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;結果: 1Mトークンあたり、DeepSeek-V4-Proは消費するのは～だけ&amp;lt;strong&amp;gt;27%の推論FLOPs&amp;lt;/strong&amp;gt; et &amp;lt;strong&amp;gt;10% の KV キャッシュのサイズ&amp;lt;/strong&amp;gt;DeepSeek-V3.2 と比較した場合の、以前のモデル。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;特に、技術レポート（図9）は発表しています： `Retrieval performance remains highly stable within a 128K context window.&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_セッション1_8安堵&amp;quot;&amp;gt;セッション1-8：安堵&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;私はDeepSeek-V4-Proとともに8回のセッションを過ごしました`codebase-gradle`. 8回のセッションで、幻覚ひとつもなく、でっち上げたクラスひとつもなく、命名の混乱ひとつもなく。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;セッション 1 : 実装`CodebaseYmlConfig` et &amp;lt;code&amp;gt;CodebaseYmlAnonymizer&amp;lt;/code&amp;gt;. 350行のKotlin、インラインテスト、すべてコンパイル。セッション4：追加`SnapshotManager`ツリービュー, ファイルの収集, ファイルごとのAsciiDocレンダリング。 279行、ゼロエラー。 セッション7: デバッグの`renderFileSection()`4種類の異なる匿名化ツールを解決における曖昧さなく管理しなければならなかった。3つのメッセージで解決した。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;レイテンシはよりも高い &amp;lt;code&amp;gt;Kimi&amp;lt;/code&amp;gt; — 思考モードでの1回の回答あたり約10〜12秒。ただし、修正率はほぼゼロ。私はエージェントのミスを直すために時間を費やしていません。私は彼と &amp;lt;strong&amp;gt;とともに&amp;lt;/strong&amp;gt; コードを書いています。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_決定的なテスト100kトークンのリファクタリング&amp;quot;&amp;gt;決定的なテスト：100Kトークンのリファクタリング&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;セッション8では、累積コンテキストが100Kトークンを超えます。私は重いリファクタリングを要求します：インライン検証の4つのタスクを抽出するの`build.gradle.kts`JUnit5テストファイルへ向かって`buildSrc/src/test/`.&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;エージェントは、3段階の計画を提案しています：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;olist arabic&amp;quot;&amp;gt;
&amp;lt;ol class=&amp;quot;arabic&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;既存のケースを移行してテストクラスを作成&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;JUnit5およびKotestの依存関係を追加する`buildSrc/build.gradle.kts`&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;インラインコードを削除する`build.gradle.kts`&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ol&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;プランは正しい。実行はきれいだ。さらに私が見逃していたエッジケースも特定している：Jackson の依存関係が重複している部分の間で`buildscript {}` et `buildSrc/build.gradle.kts`移行中に統一しなければならないもの&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;100K トークンのコンテキスト、そしてエージェントは思い出すが`CodebaseYmlAnonymizer.TOKEN_MASK`です`&amp;quot;&amp;lt;strong&amp;gt;*&amp;lt;/strong&amp;gt;&amp;quot;`, が`GitConfig.resolvedToken()&amp;lt;code&amp;gt;は 拡張関数 が 定義されている`readme.kt&amp;lt;/code&amp;gt;、そしてそれが`SnapshotManager.PRUNED_DIRS`除外する`build`, &amp;lt;code&amp;gt;.gradle&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;.git&amp;lt;/code&amp;gt;。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;それが違いです。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_フェイストゥフェイス_比較メトリクス&amp;quot;&amp;gt;フェイス・トゥ・フェイス : 比較メトリクス&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;table class=&amp;quot;tableblock frame-all grid-all stretch&amp;quot;&amp;gt;
&amp;lt;colgroup&amp;gt;
&amp;lt;col style=&amp;quot;width: 25%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 25%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 25%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 25%;&amp;quot;&amp;gt;
&amp;lt;/colgroup&amp;gt;
&amp;lt;thead&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;th class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;基準&amp;lt;/th&amp;gt;
&amp;lt;th class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;キミ K2.6&amp;lt;/th&amp;gt;
&amp;lt;th class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;GLM-5.1&amp;lt;/th&amp;gt;
&amp;lt;th class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;DeepSeek-V4-Pro&amp;lt;/th&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/thead&amp;gt;
&amp;lt;tbody&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;最大のコンテキスト&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;256K&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;200K&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;1M&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;注意メカニズム&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;MLA純&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;MLA + DSA&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;CSA + HCA ハイブリッド&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;総パラメータ&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;1T&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;744B&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;1.6T&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;有効な設定&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;32B&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;未公開&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;49B&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;観測された劣化しきい値&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;~60K tokens&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;~120K tokens&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;~128K tokens&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;先の振る舞い&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;大量の幻覚&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;表面の混乱&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;ゆっくりとした進行的な劣化&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;安定性 NIAH&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;未公開&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;100% @128K (DSA)&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;128K まで安定 (図 9)&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;MRCR @128K&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;未公開&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;未公開&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;Gemini 3.1 Proより優れている&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;放棄前に開催されたセッション&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;2&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;3&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;8 (そして続く)&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;修正時間 / コード時間&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;60%&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;30%&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;amp;lt;5%&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;平均レイテンシ (思考モード)&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;8 s&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;15 s&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;11 s&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;信頼係数*&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;2/10&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;6/10&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;9/10&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/tbody&amp;gt;
&amp;lt;/table&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;em&amp;gt;*信頼係数 = 主観的な私のエージェントのコードを取り込み、コミットする能力の尺度であり、行ごとのレビューなし。&amp;lt;/em&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div id=&amp;quot;diag-radar&amp;quot; class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
skinparam backgroundColor #FEFEFE
skinparam defaultTextAlignment center

title レーダー比較 — 3 LLMによる支援ソフトウェア開発
legend right
  |= Couleur |= Modèle |
  | &amp;amp;lt;#FF5252&amp;amp;gt; | Kimi K2.6 |
  | &amp;amp;lt;#FFC107&amp;amp;gt; | GLM-5.1 |
  | &amp;amp;lt;#4CAF50&amp;amp;gt; | DeepSeek-V4-Pro |
endlegend

rectangle &amp;quot; &amp;quot; as space #FFFFFF

rectangle &amp;quot;一貫性
80K+ トークン&amp;quot; as coh #F5F5F5
rectangle &amp;quot;品質
コード&amp;quot; as qual #F5F5F5
rectangle &amp;quot;建築的思考&amp;quot; as arch #F5F5F5
rectangle &amp;quot;抵抗
幻覚&amp;quot; as hall #F5F5F5
rectangle &amp;quot;速度
(開発経験)&amp;quot; as speed #F5F5F5
rectangle &amp;quot;知�識
Gradle/Kotlin&amp;quot; as kg #F5F5F5
rectangle &amp;quot;修正の\n率&amp;quot; as corr #F5F5F5

coh --&amp;amp;gt; qual
qual --&amp;amp;gt; arch
arch --&amp;amp;gt; hall
hall --&amp;amp;gt; speed
speed --&amp;amp;gt; kg
kg --&amp;amp;gt; corr

note top of coh
  Kimi      ████░░░░░░ 4/10
  GLM       ██████░░░░ 6/10
  DeepSeek  █████████░ 9/10
end note

note top of qual
  Kimi      ███████░░░ 7/10 (sous 60K)
  GLM       ████████░░ 8/10
  DeepSeek  █████████░ 9/10
end note

note top of arch
  Kimi      █████░░░░░ 5/10
  GLM       ███████░░░ 7/10
  DeepSeek  █████████░ 9/10
end note

note top of hall
  Kimi      ██████░░░░ 6/10 → ██░░░░░░░░ 2/10 (&amp;amp;gt; 60K)
  GLM       ███████░░░ 7/10
  DeepSeek  █████████░ 9/10
end note

note top of speed
  Kimi      █████████░ 9/10
  GLM       ██████░░░░ 6/10
  DeepSeek  █████░░░░░ 5/10
end note

note top of kg
  Kimi      ███████░░░ 7/10
  GLM       ███████░░░ 7/10
  DeepSeek  █████████░ 9/10
end note

note top of corr
  Kimi      ██░░░░░░░░ 2/10 (beaucoup de corrections)
  GLM       █████░░░░░ 5/10
  DeepSeek  ██████████ 10/10 (presque rien à corriger)
end note

@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_なぜdeepseek_v4_proはソフトウェア開発で勝つのか&amp;quot;&amp;gt;なぜDeepSeek-V4-Proはソフトウェア開発で勝つのか&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;DeepSeek-V4-Proの優位性は単一の要因によるものではなく — 収束である：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_1_csahca_アーキテクチャはコードに最適化されています&amp;quot;&amp;gt;1. CSA+HCA アーキテクチャはコードに最適化されています&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;支援されたソフトウェア開発は、長文脈注意のための*極端*なユースケースです。必要なもの： - ローカルな精度 (このクラスは何を継承しているのか？このメソッドはどこで定義されているのか？) →&amp;lt;strong&amp;gt;放送監視委員会&amp;lt;/strong&amp;gt; - 全体像（このモジュールはなぜ存在するのか？四つの匿名化ツールはどのように連携するのか？） →&amp;lt;strong&amp;gt;HCA&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;Kimi と MLA だけは局所的な精度を管理するが、60K を超えると全体像を見失う。GLM と DSA は全体像を改善するが、単一レベルのままである。DeepSeek は両方を明示的に組み合わせる。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_2_eagerコンテキストは彼彼女の快適ゾーン&amp;quot;&amp;gt;2. EAGERコンテキストは彼/彼女の快適ゾーン&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;私のガバナンスシステムは起動時に約30Kトークンのルールとバックログを読み込みます。128Kまでの安定したウィンドウがあるため、DeepSeekはセッションの交換に約100Kトークンの余裕があります。これは、Kimiが劣化なく処理できる量の3〜4倍です。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;em&amp;gt;__&amp;lt;/em&amp;gt; 128Kの完璧な安定性ウィンドウは、私のニーズに正確に合っています：EAGERが30K＋交換が70K＝20〜30メッセージの生産的なセッションで、決してグリーンゾーンから外れません。 (empty)&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_3_品質遅延比はフローに最適だ&amp;quot;&amp;gt;3. 品質/遅延比はフローに最適だ&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;はい、DeepSeek-V4-ProはKimiより遅いです（11s vs 8s）。しかし、&amp;lt;strong&amp;gt;total&amp;lt;/strong&amp;gt; タスクの時間はずっと短いです。なぜなら、エージェントの幻覚を修正するために20分を費やさないからです。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;開発者は回答のレイテンシを測定しない。開発者は「質問を投げる」のと「コードが自分のリポジトリにあり動作する」の間の時間を測定する。この指標では、DeepSeek-V4-Proが3つの中で最も速い。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_学んだ教訓_vibe_codingのためのllmの選び方&amp;quot;&amp;gt;学んだ教訓 : Vibe CodingのためのLLMの選び方&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;一時的なランキングを超えて、この経験から、ベンチマークには記載されていない基準で、LLMをソフトウェア開発支援のために評価する方法を学びました。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;olist arabic&amp;quot;&amp;gt;
&amp;lt;ol class=&amp;quot;arabic&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;アーキテクチャを見て、発表されたコンテキストサイズを見ないで。&amp;lt;/strong&amp;gt;— 256Kのコンテキストを謳っているがMLAしか持っていないモデルは、Kimiのようになる：理論的には能力があるが、実際には60Kを超えると使い物にならない。&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;あなたのコンテキストでテストしてください、汎用的なベンチマークではなく&amp;lt;/strong&amp;gt;— 私の30Kトークンの初期AsciiDocプロンプトは、絶対ルールとバックログを含んでおり、HLEまたはAIMEの質問とは関係ありません。&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;レイテンシーは、品質がついてくる限り敵ではない&amp;lt;/strong&amp;gt;— 正しいコードを生成する遅いモデルは、間違ったコードを生成する速いモデルよりも速い。&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;公開された技術報告書がないモデルには注意しろ&amp;lt;/strong&amp;gt;チームが注意アーキテクチャをドキュメントしないのは、長いコンテキストでのパフォーマンスへの自信がないからだ。&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ol&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div id=&amp;quot;diag-decision-tree&amp;quot; class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
skinparam backgroundColor #FEFEFE
skinparam defaultTextAlignment center
skinparam wrapWidth 260

title 意思決定木 — 開発支援のためのLLMの選び方
start

:Contexte initial\n&amp;amp;gt; 20K tokens ?;

if (Oui) then
  :Architecture d&amp;#39;attention\nhybride ou multi-niveau ?;

  if (CSA+HCA) then
    :DeepSeek-V4-Pro
    Fenetre stable 128K
    Ideal pour gouvernance EAGER;
    stop
  elseif (MLA + DSA) then
    :GLM-5.1
    Correct jusqu&amp;#39;a ~120K
    Latence elevee;
    stop
  else (MLA seul)
    :Kimi K2.6 (sessions courtes)
    ou eviter pour long contexte
    Chercher un modele avec
    sparse attention;
    stop
  endif
else (Contexte &amp;amp;lt; 20K)
  :N&amp;#39;importe lequel fonctionne.
  Privilegier la latence.;
  stop
endif

@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_エージェントガバナンスはこの中でどうなの&amp;quot;&amp;gt;エージェントガバナンスはこの中でどうなの？&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;この経験は、私がEager/Lazyガバナンスに関する記事以来主張してきた点を裏付けます：&amp;lt;strong&amp;gt;LLMの品質とガバナンスの品質は乗法的であり、加法的ではない。&amp;lt;/strong&amp;gt;。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;Kimi K2.6 とともに、私のガバナンスは完璧だった — しかし、モデルが情報を薄めた。結果：完璧なガバナンス × ハルシネーション = ゼロ。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;DeepSeek-V4-Pro を使用すると、EAGER ガバナンス (ルール 30K トークン) + LAZY (セッション アーカイブ、技術的参照) + Hot/Warm/Cold (ローテーション バックアップ) が組み合わさり、各層が相互に強化し合うエコシステムが形成されます。エージェントはルールを目の前に持つ (EAGER)、履歴を参照できる (LAZY)、そしてコンテキストはバックアップのローテーションにより決して飽和状態になりません。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;em&amp;gt;&amp;lt;em&amp;gt;_ 良いLLMがガバナンスなしでは、ハンドルのないフェラーリのエンジンのようだ。良いガバナンスが優れたLLMなしでは、エンジンのないハンドルのようだ。DeepSeek-V4-Pro + 私のガバナンスエージェント = 運転している感覚を初めて味わった瞬間だ。 &amp;lt;/em&amp;gt;_&amp;lt;/em&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;ローテーションバックアップメカニズム（10セッションごとまたは500行以上のEAGERごとにローテーション）は、128Kのコンテキストを保持できるモデルと組み合わせると真価を発揮します：アクティブな10セッションのスライドウィンドウは、コンテキストを新鮮に保ち、決して劣化ゾーンを超えることはありません。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_技術的な情報源&amp;quot;&amp;gt;技術的な情報源&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;私は実証的な経験を公式な技術報告書と照らし合わせて、観察結果を検証しました：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;olist arabic&amp;quot;&amp;gt;
&amp;lt;ol class=&amp;quot;arabic&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;DeepSeek-V4 Technical Report&amp;lt;/strong&amp;gt; — PDF 取得元https://huggingface.co/deepseek-ai/DeepSeek-V4-Flash[ハギングフェイス]. Figure 9 : &amp;quot;Retrieval performance remains highly stable within a 128K context window. While a performance degradation becomes visible beyond the 128K mark, the model&amp;amp;#8217;s retrieval capabilities at 1M tokens remain remarkably strong.&amp;quot; CSA+HCAアーキテクチャはセクション2.3で文書化されています。&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;GLM-5 テクニカルレポート&amp;lt;/strong&amp;gt; —https://arxiv.org/abs/2602.15763[arXiv:2602.15763]. DSA は continued pre-training を通じて導入され、「構築時に損失なし」。最大コンテキスト 202,752 トークン。表 3/5/6 は、長コンテキストでの性能を代替手法（SWA、Gated DeltaNet、SimpleGDN）と比較して記録しています。&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;Kimi K2.6 モデルカード&amp;lt;/strong&amp;gt; —https://huggingface.co/moonshotai/Kimi-K2.6[ハギングフェイス]. MLA、最大コンテキスト256K。エージェントタスクのしきい値を超えた discard‑all 戦略（MLA の長コンテキストにおける実用的な限界を暗示的に確認）。&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;Kimi K2 テクニカルレポート&amp;lt;/strong&amp;gt; —https://arxiv.org/abs/2507.20534[arXiv:2507.20534]. MoEアーキテクチャ, MuonClipオプティマイザ, エージェント的なパフォーマンス (HLE, BrowseComp, Terminal-Bench).&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ol&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;最も示唆に富む点：彼ら自身の評価において、Moonshot はコンテキストウィンドウが超過されたときに &amp;lt;strong&amp;gt;discard-all&amp;lt;/strong&amp;gt; (古いコンテキストの削除) 戦略を適用します。これは私が観察したことを正確に確認します：MLA だけでは 256K のウィンドウ全体で一貫性を維持することはできません。アーキテクチャが追いついていない。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_結論職人の選択&amp;quot;&amp;gt;結論：職人の選択&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;3週間と13回の実際の開発セッションの後、結論は出ました：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;table class=&amp;quot;tableblock frame-all grid-all stretch&amp;quot;&amp;gt;
&amp;lt;colgroup&amp;gt;
&amp;lt;col style=&amp;quot;width: 8.3333%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 8.3333%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 8.3333%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 8.3333%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 8.3333%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 8.3333%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 8.3333%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 8.3333%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 8.3333%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 8.3333%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 8.3333%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 8.3337%;&amp;quot;&amp;gt;
&amp;lt;/colgroup&amp;gt;
&amp;lt;tbody&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;Kimi K2.6&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;GLM-5.1&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;DeepSeek-V4-Pro&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;60K以下で優秀&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;最大120Kまで頑丈&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;どこでも支配する&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;超えては使用できない&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;表面の混乱&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;128Kまで安定&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;2 セッション、放棄&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;3セッション、放棄&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;8セッション、採択&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/tbody&amp;gt;
&amp;lt;/table&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;DeepSeek-V4-Proは、Opencodeを使用したすべてのソフトウェア開発支援セッションにおいて、私のデフォルトのLLMになりました。それは最新だからではなく、学術的なベンチマークが最高だからでもありません。しかし、30Kトークンのエージェントコンテキストを持つGradle Kotlin DSLプラグインをプッシュする開発者の実際の業務では、コンテキストが長くなっても私を裏切らない唯一のものだからです。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;CSA+HCA はアーキテクチャにおける &amp;lt;strong&amp;gt;game changer&amp;lt;/strong&amp;gt; です。ダブルレベル圧縮 + スパース化は実装の詳細ではなく、それがコードアシスタントと信頼できるチームメイトの違いを生むものです。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;em&amp;gt;&amp;lt;em&amp;gt;_ 私はDeepSeek-V4-Proを選びました。なぜなら、それは3つのうちのただ一つで、私のエージェントガバナンスを防御的な制約（「エージェントが忘れないようにどうすればいいですか？」）から攻撃的な優位（「エージェントがすべてを覚えている今、何を構築できるでしょうか？」）に変えるからです。 &amp;lt;/em&amp;gt;_&amp;lt;/em&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;hr&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;この記事は、プロジェクトにおける実際の開発13セッションの成果です。&amp;lt;/strong&amp;gt;&amp;lt;code&amp;gt;codebase-gradle&amp;lt;/code&amp;gt;, 文書化されている`.agents/sessions/`私のEager/Lazy/Hot/Warm/Coldエージェントのガバナンス手法によれば。引用されている技術的なソースは、HuggingFaceおよびarXivで公開アクセス可能です。*&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;</description>
        </item><item>
            <title>コンテキストエージェントの監査 : 自分のガバナンスが問題になるとき — そして何も失わずにそれを修正する方法</title>
            <link >https://cheroliv.com/blog/2026/0111_audit_contexte_agent_post.html</link>
            <pubDate>Mon, 27 Apr 2026 00:00:00 +0000</pubDate>
            <guid isPermaLink="false">blog/2026/0111_audit_contexte_agent_post.html</guid>
            <description>&amp;lt;div id=&amp;quot;toc&amp;quot; class=&amp;quot;toc&amp;quot;&amp;gt;
&amp;lt;div id=&amp;quot;toctitle&amp;quot;&amp;gt;Table des matières&amp;lt;/div&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel1&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_シーン_セッション051何かがおかしい&amp;quot;&amp;gt;シーン: セッション051、何かがおかしい&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_監査627行を詳細に調べる&amp;quot;&amp;gt;監査：627行を詳細に調べる&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_エンジニアリングを失う恐れ&amp;quot;&amp;gt;エンジニアリングを失う恐れ&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_解決策_split百科事典的&amp;quot;&amp;gt;解決策： split百科事典的&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_ファイルの内容_essentials&amp;quot;&amp;gt;ファイルの内容 ESSENTIALS&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_結果_50_の_eager_コンテキスト&amp;quot;&amp;gt;結果: -50% の EAGER コンテキスト&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_なぜフォルダーは_encyclopediesと呼ばれるのですか&amp;quot;&amp;gt;なぜフォルダーは `encyclopedies/`と呼ばれるのですか？&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_シリーズの論理的な続き&amp;quot;&amp;gt;シリーズの論理的な続き&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_私が違うようにやったこと&amp;quot;&amp;gt;私が違うようにやったこと&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_自分のコンテキストを監査するためのガイド&amp;quot;&amp;gt;自分のコンテキストを監査するためのガイド&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_活きたガバナンス&amp;quot;&amp;gt;活きたガバナンス&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_リンク&amp;quot;&amp;gt;リンク&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div id=&amp;quot;preamble&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;読了時間 : 14 minutes&amp;lt;/div&amp;gt;
&amp;lt;p&amp;gt;あなたは完璧なエージェントガバナンスを構築するために何週間も費やしました。Eager/Lazy、セッション終了手順、ローテーションバックアップ。システムは稼働しています。ある日、エージェントが遅くなりました。応答が薄まっています。測定したところ：自動的にロードされた1414行。そして最悪なのは、原因がコードでもバックログでもセッションアーカイブでもないことです。原因は、あなたの方法をドキュメントするファイルです。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;dlist&amp;quot;&amp;gt;
&amp;lt;dl&amp;gt;
&amp;lt;dt class=&amp;quot;hdlist1&amp;quot;&amp;gt;チック&amp;lt;/dt&amp;gt;
&amp;lt;dd&amp;gt;
&amp;lt;p&amp;gt;[]&amp;lt;/p&amp;gt;
&amp;lt;/dd&amp;gt;
&amp;lt;/dl&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_シーン_セッション051何かがおかしい&amp;quot;&amp;gt;シーン: セッション051、何かがおかしい&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;2026年4月30日、16時00分。私は現在セッション中`magic-stick`, 私のLinuxライブISOのビルドプロジェクト。Opencodeエージェントは、いつものように私のEagerファイルを自動的にロードしました —&amp;lt;code&amp;gt;AGENT.adoc&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;PROMPT_REPRISE.adoc&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;.agents/INDEX.adoc&amp;lt;/code&amp;gt;. すべてが正常です。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;ただし、返答が弱い。エージェントは推論に2秒余計に時間がかかる。彼は、3つ前のメッセージで目の前にあった詳細を忘れてしまう。これはクラッシュでもエラーでもなく、ゆっくりと劣化していくようなもので、すぐに気づくようなことではない。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;以前、セッション048で同じ経験をしました。そのとき、ガバナンスファイルの合計が5200行あることを発見しました。そこで、10セッションのスライドウィンドウを持つHot/Warm/Coldメカニズム、同じコールドウェーブ、2つのトリガーを持つセンサーを概念化しました。問題は理論的には解決しました。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;しかし、私たちはセッション051にいます。バックアップのローテーションは正常に実行されました — EAGERファイルは2087行から500行に減りました。しかし、コンテキストはまだ重いです。何かが私にはつかめない。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;端末を開いて、入力します :&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;wc -l AGENT.adoc AGENT_MODUS_OPERANDI.adoc PROMPT_REPRISE.adoc \
  .agents/INDEX.adoc .agents/SESSIONS_HISTORY.adoc \
  .agents/archives/COMPLETED_TASKS_ARCHIVE_2026-04.adoc&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-none hljs&amp;quot;&amp;gt;  287 AGENT.adoc
  627 AGENT_MODUS_OPERANDI.adoc
   51 PROMPT_REPRISE.adoc
  218 .agents/INDEX.adoc
   18 .agents/SESSIONS_HISTORY.adoc
  213 .agents/archives/COMPLETED_TASKS_ARCHIVE_2026-04.adoc
 1414 total&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;1414行。バックアップローテーションが INDEX, SESSIONS_HISTORY, COMPLETED_TASKS をうまくトリムしました — これらはきれいです。しかし、部屋に象がいることに気づいていませんでした：&amp;lt;strong&amp;gt;627 行&amp;lt;/strong&amp;gt;1つのファイルに。&amp;lt;code&amp;gt;AGENT_MODUS_OPERANDI.adoc&amp;lt;/code&amp;gt;。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;このファイルは、セッション1でEager/Lazy戦略を文書化するために私が書いたものです。これはこの方法のマニュアルです。そして、それだけでEAGERコンテキストの44%になりました。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div id=&amp;quot;diag-before-audit&amp;quot; class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
skinparam backgroundColor #FEFEFE

title コンテキスト EAGER — 1414 行
rectangle &amp;quot;AGENT_MODUS_OPERANDI
**627 行 (44%)**&amp;quot; as MOD #FFCDD2
rectangle &amp;quot;AGENT.adoc
287 行 (20%)&amp;quot; as AG #BBDEFB
rectangle &amp;quot;INDEX.adoc
218行 (15%)&amp;quot; as IDX #C8E6C9
rectangle &amp;quot;COMPLETED_TASKS
213 行 (15%)&amp;quot; as ARC #FFF9C4
rectangle &amp;quot;PROMPT_REPRISE
51 行 (4%)&amp;quot; as PRO #E1BEE7
rectangle &amp;quot;SESSIONS_HISTORY\n18行(1%)&amp;quot; as HIS #FFE0B2

note bottom of MOD
  Le fichier qui documente
  la méthode est devenu
  le plus gros poste de dépense
end note

@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;皮肉は完全だ。コンテキストを*節約*するために設計されたファイルが、コンテキストの主要な*消費者*になった。まるであなたの車の取扱説明書がエンジンよりも重いかのように。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_監査627行を詳細に調べる&amp;quot;&amp;gt;監査：627行を詳細に調べる&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;私はセクションごとに監査を行うことに決めました。削除するためではなく、*理解*するためです。EAGERにふさわしいものと、知識の損失なく他所で生きていけるものを見極めるためです。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;ここに正確な構造があります：`AGENT_MODUS_OPERANDI.adoc`そしてそこで見つけるもの :&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;table class=&amp;quot;tableblock frame-all grid-all stretch&amp;quot;&amp;gt;
&amp;lt;colgroup&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.2727%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.2727%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.2727%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.2727%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.2727%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.2727%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.2727%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.2727%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.2727%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.2727%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.2727%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.2727%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.2727%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.2727%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.2727%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.2727%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.2727%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.2727%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.2727%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.2727%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.2727%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.2727%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.2727%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.2727%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.2727%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.2727%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.2727%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.2727%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.2727%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.2727%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.2727%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.2727%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.2727%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.2727%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.2727%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.2727%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.2727%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.2727%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.2727%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.2727%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.2727%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.2727%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.2727%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.2739%;&amp;quot;&amp;gt;
&amp;lt;/colgroup&amp;gt;
&amp;lt;tbody&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;セクション&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;行&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;内容&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;既に&amp;amp;#8230;&amp;amp;#8203;に存在しています。&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;P1 — 概要&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;64&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;問題解決、基本原則、ダッシュボード対マニュアルの類似&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;バックティックコードスパン (&amp;lt;code&amp;gt;&amp;amp;#8230;&amp;amp;#8203;&amp;lt;/code&amp;gt;) をすべてそのまま保持してください — バックティックの内容、間隔、位置を決して変更しないでください。 このテキストはより大きな文の一部である可能性があります — より多くのコンテキストを要求せずにフラグメントを翻訳してください。 翻訳されたテキストのみを出力してください — 説明も commentary も導入も代替案もオプションもありません。&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;P2 — ファイル構造&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;97&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;階層構造, ロードポリシー, 何をいつロードするか&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;—&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;P3 — 絶対的なルール&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;34&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;Git は禁止、破壊的なコマンドは禁止、機密情報は禁止&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;code&amp;gt;AGENT.adoc&amp;lt;/code&amp;gt;+&amp;lt;code&amp;gt;INDEX.adoc&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;P4 — セッションライフサイクル&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;133&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;テンプレート オープニング, 作業ルール, セッション終了の6ステップ, チェックリスト&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;code&amp;gt;AGENT.adoc&amp;lt;/code&amp;gt;§セッション終了 +&amp;lt;code&amp;gt;INDEX.adoc&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;P5―メトリクスとしきい値&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;49&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;理想的なセッション（15-30分、1-3ファイル）、警告サイン&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;（空白）&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;P6 — セッションの種類&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;72&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;�検出表, 提案フォーマット, 例外&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;—&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;P7 — 継続的な改善&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;39&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;追跡指標, 週次レビュー&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;—&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;P8 — 起動チェックリスト&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;13&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;Bootstrap 新しいプロジェクト&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;(Empty)&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;P9 — 参考文献&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;30&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;参照ファイル, 外部リソース&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;code&amp;gt;AGENT.adoc&amp;lt;/code&amp;gt;(ファイル EAGER/LAZY)&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;付録 A+B&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;42&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;用語集, バージョン履歴&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;—&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/tbody&amp;gt;
&amp;lt;/table&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;判決は覆らない：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;完全な重複&amp;lt;/strong&amp;gt;(167 行) : P3, P4, P9 — すべて既に含まれている`AGENT.adoc` ou &amp;lt;code&amp;gt;INDEX.adoc&amp;lt;/code&amp;gt;, しばしば逐語的に&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;実践では一度も相談されなかった&amp;lt;/strong&amp;gt;(215 行) : P5, P6, P7, P8, 付録 — どのセッションでも一度も使われたことがないメタガバナンス&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;唯一の知識&amp;lt;/strong&amp;gt;(161 行) : P1 と P2 — LAZY/EAGER の語彙、類推、ロードポリシー&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;627行で,&amp;lt;strong&amp;gt;382 は騒音です&amp;lt;/strong&amp;gt;. そしてこれらの382行は、&amp;lt;strong&amp;gt;各セッションの開始時に&amp;lt;/strong&amp;gt; 読み込まれ、エージェントによって消費され、私が「こんにちは」と言う前に彼の注意を薄めます。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div id=&amp;quot;diag-audit-result&amp;quot; class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
skinparam backgroundColor #FEFEFE
skinparam defaultTextAlignment center

title AGENT_MODUS_OPERANDI.adoc の監査 — 627 行
left to right direction

rectangle &amp;quot;�🟡 **重複**
167 行 (27%)&amp;quot; as DUP #FFF9C4 {
  card &amp;quot;P3 — 絶対的な規則
(34行)&amp;quot; as D1
  card &amp;quot;P4 — ライフサイクル
(133 行)&amp;quot; as D2
  card &amp;quot;P9 — 参考文献
(30 行)&amp;quot; as D3
}

rectangle &amp;quot;🔴 **未参照**
215 行 (34%)&amp;quot; as JAM #FFCDD2 {
  card &amp;quot;P5 — メトリクス
(49行)&amp;quot; as J1
  card &amp;quot;P6 — 検出\n(72 行)&amp;quot; as J2
  card &amp;quot;P7 — �善
(39 行)&amp;quot; as J3
  card &amp;quot;P8 — Bootstrap
(13 行)&amp;quot; as J4
  card &amp;quot;付録 — 用語集
(42 行)&amp;quot; as J5
}

rectangle &amp;quot;🟢 **独自の知識**
161 行 (26%)&amp;quot; as UNI #C8E6C9 {
  card &amp;quot;P1 — 概要
(64 行)&amp;quot; as U1
  card &amp;quot;P2 — ファイル構造
(97 行)&amp;quot; as U2
}

note bottom of UNI
  C&amp;#39;est ÇA qu&amp;#39;il faut garder en EAGER.
  Le reste → cold storage.
end note

@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;この図がすべての鍵です。重複（黄色）は純粋なノイズです — エージェントはそれらを2回読み、異なる2つのファイルで読み取ります。未参照（赤色）は死んだドキュメントです — 慎重に書かれているが、決して使われません。緑だけが、エージェントが他では見つけることができない知識を含んでいます。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_エンジニアリングを失う恐れ&amp;quot;&amp;gt;エンジニアリングを失う恐れ&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;この段階で、私は目の前に証拠がある：減らさなければならない。&amp;lt;code&amp;gt;AGENT_MODUS_OPERANDI.adoc&amp;lt;/code&amp;gt;. しかし、私は躊躇しています。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;このファイルは手書きで書きました。各セクションは実際のセッションで学んだ教訓の結果です。P3の部分はある`rm -rf`偶発的な上で`bakery-plugin`実際のFirebaseトークンを消費させられた。P4部分は、アーカイブし忘れて途中で方向を見失った15回のセッションの結果です。この6ステップの手順は書籍から生まれたものではなく、苦痛から生まれたものだ。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;これらのセクションを削除すれば、自分のエンジニアリングの歴史を捨てることになる。これらを生み出した教訓、それらを発見したセッション、二度と繰り返したくないミス。これはテキストではない――結晶化された経験だ。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;ここで私が、解決を導く原理を定式化します :&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;em&amp;gt;&amp;lt;em&amp;gt;_ &amp;lt;strong&amp;gt;絶対に削除しないで。常に移動させて。&amp;lt;/strong&amp;gt;知識はプロジェクトから消える必要はない。ただ、必要ないときは自動的に読み込まれないようにすればよい。 &amp;lt;/em&amp;gt;_&amp;lt;/em&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_解決策_split百科事典的&amp;quot;&amp;gt;解決策： split百科事典的&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;私が提案するモデルはシンプルで、Wikipediaが成長した方法からインスピレーションを得ています : 記事が長くなりすぎたら切るのではなく — 詳細な記事を作成し、主要な記事に要約を残します。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;のために`AGENT_MODUS_OPERANDI.adoc`, これが与えられます :&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;olist arabic&amp;quot;&amp;gt;
&amp;lt;ol class=&amp;quot;arabic&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;�抽出する&amp;lt;/strong&amp;gt;新しいファイルの161行のユニークな知識 (P1 + P2)&amp;lt;code&amp;gt;LAZY_EAGER_ESSENTIALS.adoc&amp;lt;/code&amp;gt;— 約50行に圧縮され、厳密にEAGER&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;名前を変更&amp;lt;/strong&amp;gt; &amp;lt;code&amp;gt;AGENT_MODUS_OPERANDI.adoc&amp;lt;/code&amp;gt; en &amp;lt;code&amp;gt;.agents/encyclopedies/LAZY_EAGER_ENCYCLOPEDIE.adoc&amp;lt;/code&amp;gt;— 元のファイルは627行で、*intact*の状態でコールドストレージに保存されています&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;決して充電するな&amp;lt;/strong&amp;gt;百科事典ファイルは自動的に — それは人間のため、将来の蒸留のため、そして6ヶ月後にもっと良いモデルで呼び出すエージェントのために存在しています。&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ol&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div id=&amp;quot;diag-split-solution&amp;quot; class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
skinparam backgroundColor #FEFEFE
skinparam defaultTextAlignment center

title 分割百科事典 — AGENT_MODUS_OPERANDI
left to right direction

rectangle &amp;quot;**AGENT_MODUS_OPERANDI.adoc**
627 行
(分割前)&amp;quot; as BEFORE #FFCDD2 {
}

rectangle &amp;quot; &amp;quot; as ARROW1
rectangle &amp;quot; &amp;quot; as ARROW2

rectangle &amp;quot;**LAZY_EAGER_ESSENTIALS.adoc**
**~50 行 — EAGER**&amp;quot; as ESS #C8E6C9 {
  card &amp;quot;P1凝縮
(15行)&amp;quot; as E1
  card &amp;quot;P2凝縮版\n(35 行)&amp;quot; as E2
}

rectangle &amp;quot;**.agents/encyclopedies/**
**LAZY_EAGER_ENCYCLOPEDIE.adoc**
627 行 — COLD&amp;quot; as ENC #BBDEFB {
  card &amp;quot;P1を付録へ
(完全, 無傷)&amp;quot; as C1
}

BEFORE -[#4CAF50]-&amp;amp;gt; ESS : &amp;quot;クリティカルな知識の抽出&amp;quot;
BEFORE -[#2196F3]-&amp;amp;gt; ENC : &amp;quot;完全な保存
エンジニアリングの&amp;quot;

note bottom of ESS
  Chargé automatiquement
  en début de session
  → L&amp;#39;agent comprend le vocabulaire
end note

note bottom of ENC
  Jamais chargé automatiquement
  Consultable par l&amp;#39;humain
  Matériau brut pour distillation future
end note

@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;名前`encyclopedies/`それは軽々しいことではない。百科事典はアーカイブのファイルではなく、整理された知識の集まりで、参照できるが持ち運びはできない。メトロではEncyclopédie Universalisを読まない。これを図書館に置き、具体的な質問があるときにそこに行く。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;これはまさにこのフォルダーの役割です：冷たく、構造化され、包括的な参照ライブラリ — エージェントが自動的に触れないもの。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_ファイルの内容_essentials&amp;quot;&amp;gt;ファイルの内容 ESSENTIALS&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;これが新しいファイルの具体的な姿です。&amp;lt;code&amp;gt;LAZY_EAGER_ESSENTIALS.adoc&amp;lt;/code&amp;gt;, 抽出および圧縮され、P1 と P2 から：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-asciidoc hljs&amp;quot; data-lang=&amp;quot;asciidoc&amp;quot;&amp;gt;= Stratégie LAZY/EAGER — Principes Essentiels

[abstract]
Ce fichier définit la stratégie de gestion du contexte agent.
Chargé automatiquement (EAGER) en début de session.

== Principes

|===
| EAGER | LAZY
| Tableau de bord | Manuel du propriétaire
| Chargé automatiquement | Chargé sur demande
| &amp;amp;lt;= 100 lignes, &amp;amp;lt;= 10k tokens | Illimité, détaillé
| Règles absolues, mission courante | Archives, historique, références
|===

== Politique de Chargement

|===
| Fichier | Type | Quand charger
| PROMPT_REPRISE.adoc | EAGER | Début session (auto)
| *_ESSENTIALS.adoc | EAGER | Début session si EPIC active
| .agents/INDEX.adoc | EAGER | Début session (auto)
| *_REFERENCE.adoc | LAZY | Sur besoin (détails architecture)
| .agents/sessions/N-*.adoc | LAZY | Sur demande (détails session)
| .agents/encyclopedies/*.adoc | COLD | Jamais auto (humain seulement)
|===

== Comment l&amp;#39;Agent Sait Quoi Charger

Début session → PROMPT_REPRISE + INDEX + ESSENTIALS actifs.
Besoin de détails → charger les *_REFERENCE et sessions/ en LAZY.
Connaissance froide → encyclopedies/, jamais automatique.&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;50行。これがエージェントがメカニズムを理解するために必要なすべてだ。それ以外―レッスンの履歴、詳細なアナロジー、ステップバイステップの手順、付録―はすべて百科事典にある。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;そして最も重要なこと:&amp;lt;strong&amp;gt;何も削除されていません&amp;lt;/strong&amp;gt;. 627行のエンジニアリングラインはまだそこにあります、その中`.agents/encyclopedies/LAZY_EAGER_ENCYCLOPEDIE.adoc`. それらはただ本棚に置かれているだけで、作業台の上にあるわけではありません。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_結果_50_の_eager_コンテキスト&amp;quot;&amp;gt;結果: -50% の EAGER コンテキスト&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;分割前：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-none hljs&amp;quot;&amp;gt; 287 AGENT.adoc
 627 AGENT_MODUS_OPERANDI.adoc
  51 PROMPT_REPRISE.adoc
 218 .agents/INDEX.adoc
  18 .agents/SESSIONS_HISTORY.adoc
 213 .agents/archives/COMPLETED_TASKS_ARCHIVE_2026-04.adoc
1414 total&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;分割後：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-none hljs&amp;quot;&amp;gt; 287 AGENT.adoc
  50 LAZY_EAGER_ESSENTIALS.adoc       ← remplace 627 lignes
  51 PROMPT_REPRISE.adoc
 218 .agents/INDEX.adoc
  18 .agents/SESSIONS_HISTORY.adoc
 213 .agents/archives/COMPLETED_TASKS_ARCHIVE_2026-04.adoc
 837 total                              ← -41%&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div id=&amp;quot;diag-after-audit&amp;quot; class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
skinparam backgroundColor #FEFEFE

title エン�ンサイクロペディック分割後の EAGER コンテキスト — 837 行 (－41%)
rectangle &amp;quot;AGENT.adoc
287行(34%)&amp;quot; as AG #BBDEFB
rectangle &amp;quot;INDEX.adoc
218行 (26%)&amp;quot; as IDX #C8E6C9
rectangle &amp;quot;COMPLETED_TASKS
213 行 (25%)&amp;quot; as ARC #FFF9C4
rectangle &amp;quot;PROMPT_REPRISE
51 行 (6%)&amp;quot; as PRO #E1BEE7
rectangle &amp;quot;ESSENTIALS
50 行 (6%)&amp;quot; as ESS #A5D6A7
rectangle &amp;quot;SESSIONS_HISTORY
18 行 (2%)&amp;quot; as HIS #FFE0B2

note bottom of ESS
  De 627 → 50 lignes
  577 lignes d&amp;#39;ingénierie
  préservées en cold storage

  Rien de perdu. Tout de relocalisé.
end note

@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;最大の消費者（&amp;lt;code&amp;gt;AGENT_MODUS_OPERANDI&amp;lt;/code&amp;gt;, 627行）は50行のファイルに置き換えられました。利益は即座に得られます：577行のコンテキストが解放されました。エージェントは安堵しています。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;そして中で`.agents/encyclopedies/`元のファイルは627行で待っています。変更されていません。すべてのセクション — 重複しているものも、まだ使われていないものも含めて — 。なぜなら、いつかより良いモデルまたは人間のデータサイエンティストがこれらの角度、これらの受け入れられた冗長性、これらの学んだ教訓を交差させたくなるからです。そしてその日には、原材料がそこにあるでしょう。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_なぜフォルダーは_encyclopediesと呼ばれるのですか&amp;quot;&amp;gt;なぜフォルダーは `encyclopedies/`と呼ばれるのですか？&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;名前の選択は装飾的ではない。それはメカニズムの哲学をエンコードする。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;アーカイブ&amp;lt;/strong&amp;gt; (&amp;lt;code&amp;gt;archives/&amp;lt;/code&amp;gt;) 歴史的なデータが年代順に整理されて含まれています — 月次の COMPLETED_TASKS のように。 &amp;lt;strong&amp;gt;backup&amp;lt;/strong&amp;gt; (&amp;lt;code&amp;gt;backup/&amp;lt;/code&amp;gt;)はタイムスタンプ付きスナップショットである — 過去の状態のバックアップコピー&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;百科事典&amp;lt;/strong&amp;gt;、これは別のものだ。これはテーマ別の知識の集まりであり、主題ごとに構成され、包括的だが非線形である。百科事典は最初から最後まで読むものではない。そこに飛び込んで特定の質問に答える。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;これはまさにこのファイルの契約です：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;table class=&amp;quot;tableblock frame-all grid-all stretch&amp;quot;&amp;gt;
&amp;lt;colgroup&amp;gt;
&amp;lt;col style=&amp;quot;width: 6.25%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 6.25%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 6.25%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 6.25%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 6.25%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 6.25%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 6.25%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 6.25%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 6.25%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 6.25%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 6.25%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 6.25%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 6.25%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 6.25%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 6.25%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 6.25%;&amp;quot;&amp;gt;
&amp;lt;/colgroup&amp;gt;
&amp;lt;tbody&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;ファイル&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;役割&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;アクセス&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;粒度&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;code&amp;gt;archives/&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;過去のデータ（月ごとに完了したタスク）&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;LAZY, 構造化された&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;年代順の&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;code&amp;gt;backup/&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;冷たいスナップショット（10セッションの波）&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;COLD, 完全コピー&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;時系列の&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;code&amp;gt;encyclopedies/&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;包括的なテーマ別の知識（方法論、パターン）&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;COLD、決してオート&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;テーマ&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/tbody&amp;gt;
&amp;lt;/table&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;この区別は雑多になることを防ぎます。各ファイルは、*作成時*ではなく、*その中身*に従って、どこに置くべきかを知っています。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_シリーズの論理的な続き&amp;quot;&amp;gt;シリーズの論理的な続き&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;最初の2つの記事を読んだ場合、ここで3つのピースがどのように組み合わされるかを示します：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div id=&amp;quot;diag-trilogie&amp;quot; class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
skinparam backgroundColor #FEFEFE
skinparam defaultTextAlignment center
skinparam wrapWidth 220

title エージェントガバナンス三部作
left to right direction

package &amp;quot;�📖 **Article 0108**
戦略 Eager/Lazy&amp;quot; as A1 #E8F5E9 {
  card &amp;quot;エージェントメモリ
セッション間&amp;quot; as M1
  card &amp;quot;EAGER ファイル
(自動的にロードされた)&amp;quot; as M2
  card &amp;quot;ファイル LAZY
(オンデマンド)&amp;quot; as M3
  card &amp;quot;6段階の手順&amp;quot; as M4
}

package &amp;quot;�🧊 **Article 0110**
メカニズム ホット/ウォーム/コールド&amp;quot; as A2 #FFF9C4 {
  card &amp;quot;老化
コンテキストの&amp;quot; as V1
  card &amp;quot;スライドウィンドウ
10セッション&amp;quot; as V2
  card &amp;quot;�寒波
同じ&amp;quot; as V3
  card &amp;quot;二つのトリガーを備えたセンサー&amp;quot; as V4
}

package &amp;quot;�🔍 **Article 0111**\n監査 + 百科事典ソリューション&amp;quot; as A3 #BBDEFB {
  card &amp;quot;ファイルの監査
EAGER&amp;quot; as E1
  card &amp;quot;特定
廃棄物&amp;quot; as E2
  card &amp;quot;Split
ESSENTIALS/百科事典&amp;quot; as E3
  card &amp;quot;保存
エンジニアリングの&amp;quot; as E4
}

A1 --&amp;amp;gt; A2 : &amp;quot;メモリは増大する\n→ 経年劣化のメカニズムが必要&amp;quot;
A2 --&amp;amp;gt; A3 : &amp;quot;経年だけでは不十分です
→ 監査する必要があるもの
EAGERである価値がある&amp;quot;

note bottom of A3
  ✅ Les trois couches sont en place
  sur 6 projets actifs
end note

@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;0108&amp;lt;/strong&amp;gt;回答: «エージェントに二つのセッションの間で記憶を与える方法は？&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;0110&amp;lt;/strong&amp;gt;それに答える : « この記憶がエージェントを窒息させないようにどう防ぐか？&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;0111&amp;lt;/strong&amp;gt;返答: 「そして問題がアーカイブのサイズではなく、EAGERに設定することを*選んだ*ものである場合は？」&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;最初の論文は構造を構築した。二番目は老化メカニズムを追加した。三番目は内容を監査し — そして方法論自身が問題になったことを発見した。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_私が違うようにやったこと&amp;quot;&amp;gt;私が違うようにやったこと&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;振り返ってみると、最初の設計ミスに気づく。`AGENT_MODUS_OPERANDI.adoc`これは単一のドキュメントとして作成され、マニフェストとなりました。それは思考を形式化するための正しいアプローチでした。しかし、思考が形式化された後、ドキュメントはすぐに分割されるべきでした：EssentialはEAGER、包括的はcoldとして。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;私は文書に誇りを持っていたので、それを行わなかった。627行の純粋なエンジニアリング、手書きで書かれ、各セクションはセッションのレッスンの成果だった。それは私の作品だった。そして、あらゆる作者のように、私はそれを分割するのに苦労した。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;レッスン：&amp;lt;strong&amp;gt;文書が良いからといって、自動的に読み込まれるべきではない。&amp;lt;/strong&amp;gt;. コンテンツの品質は、エージェントの直近の文脈への関連性とは関係がない。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;今日、ルールは単純です：EAGERコンテキストにおいて100行を超えるドキュメントはすべて疑わしいものです。監査の対象となります。非難ではなく監査です。問題は決して「削除すべきか？」ではなく「各セッションでロードすべきか？」です。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_自分のコンテキストを監査するためのガイド&amp;quot;&amp;gt;自分のコンテキストを監査するためのガイド&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;最初の2つの記事に従い、独自のEager/Lazyガバナンスを構築した場合、監査の5ステップ手順は次の通りです：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;olist arabic&amp;quot;&amp;gt;
&amp;lt;ol class=&amp;quot;arabic&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;�測る&amp;lt;/strong&amp;gt; : `wc -l`すべてのEAGERファイルに対して。合計は1000行以下であるべきです。&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;最大のものを特定する&amp;lt;/strong&amp;gt;: 合計の20%以上を占めるファイルが疑わしいファイル第1位です。&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;セクションごとに監査&amp;lt;/strong&amp;gt;: 各セクションについて、自分に問いかける 「この情報は他のところにすでにありますか？ エージェントは他のファイルで既にこれを読みましたか？ これは過去5セッションで使用されましたか？」&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;分類器&amp;lt;/strong&amp;gt;重複、一度も使用されていない、独自の知識。&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;分割または再配置&amp;lt;/strong&amp;gt;: 何が独自かつ重要であるか → ESSENTIALS コンパクト化。それ以外すべて →&amp;lt;code&amp;gt;encyclopedies/&amp;lt;/code&amp;gt;。&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ol&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div id=&amp;quot;diag-audit-checklist&amp;quot; class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
skinparam backgroundColor #FEFEFE
skinparam defaultTextAlignment center

title コンテキストエージェントの監査手順 — 5ステップ
start

:1. **Mesurer**\n`wc -l *.adoc .agents/*.adoc`;

if (Total &amp;amp;gt; 1000 lignes ?) then (oui)
  :⚠️ Contexte trop lourd;
else (non)
  :✅ Contexte OK;
  stop
endif

:2. **Identifier le suspect**\nLe fichier &amp;amp;gt; 20% du total;

:3. **Auditer section par section**\nPour chaque section :\n• Déjà ailleurs ? → doublon\n• Jamais servi ? → mort\n• Information unique ? → critique;

:4. **Classifier**\n🟡 Doublons → à retirer de l&amp;#39;EAGER\n🔴 Jamais utilisé → cold storage\n🟢 Connaissance unique → à garder;

:5. **Splitter**\n🟢 → ESSENTIALS (~50 lignes, EAGER)\n🟡🔴 → encyclopedies/ (cold storage);

:✅ Contexte optimisé\nsans perte d&amp;#39;ingénierie;

stop

@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;この手順は15分かかります。50セッションのプロジェクトでは、今後の各セッションで数百トークンを節約できます。ROIは即座に現れます。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_活きたガバナンス&amp;quot;&amp;gt;活きたガバナンス&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;この3部作の記事シリーズから私が学んだことは、エージェントガバナンスは完成品ではないということです。それは&amp;lt;strong&amp;gt;生きている生物&amp;lt;/strong&amp;gt;. 彼女はプロジェクトとともに成長する。 彼女は成長に伴う病気にかかる。 彼女は定期的なチェックアップが必要だ。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;セッション 048 は、アーカイブが膨らんでいることを明らかにしました。セッション 051 は、方法論そのものが膨らんでいることを明らかにしました。セッション 060 はおそらく別の何かを明らかにするでしょう。それは普通です。それは健全です。決して自己反省しないガバナンスは死んだガバナンスです。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;三つのメカニズム — Eager/Lazy、Hot/Warm/Cold、百科事典的分割 — が配置され、コンテキストの飽和に対する深層防御システムを形成しています。いずれも単独では十分ではありません。組み合わせると、互いに補完し合います：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;熱意がある/怠惰な&amp;lt;/strong&amp;gt;可用性で情報を構造化する&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;暑い/温かい/寒い&amp;lt;/strong&amp;gt;情報を*新鮮さによって*構造化する&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;百科全書の監査&amp;lt;/strong&amp;gt;情報を*密度で*構造化する&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div id=&amp;quot;diag-defense-in-depth&amp;quot; class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
skinparam backgroundColor #FEFEFE
skinparam nodeBackgroundColor #E3F2FD

title コンテキストの飽和に対する深層防御
node &amp;quot;**エージェントコンテキスト**
~800 行
健康&amp;quot; as CTX #C8E6C9

node &amp;quot;レイヤー 1\n**EAGER / LAZY**&amp;quot; as C1 #BBDEFB
node &amp;quot;�層2
**ホット / ウォーム / コールド**&amp;quot; as C2 #BBDEFB
node &amp;quot;層 3
**基本 / 百科事典**&amp;quot; as C3 #BBDEFB

CTX --&amp;amp;gt; C1 : &amp;quot;構造による\n**可用性**&amp;quot;
CTX --&amp;amp;gt; C2 : &amp;quot;構造による\n**新鮮さ**&amp;quot;
CTX --&amp;amp;gt; C3 : &amp;quot;構造による
**密度**&amp;quot;

note bottom of C3
  Les trois couches sont nécessaires.
  Aucune n&amp;#39;est suffisante seule.
end note

@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;これらの3つの層で、エージェントのコンテキストについて`magic-stick`2087行（あらゆる最適化を行う前）から約800行に減少 — つまり2.6倍に削減されました。ドキュメントの1行も、セッションのアーカイブも、学んだ教訓も1つも失っていません。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;全部ここにある。ただ、もっときれいに片付けられている。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_リンク&amp;quot;&amp;gt;リンク&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;記事 0108 — アイガー／レイジー戦略 :&amp;lt;a href=&amp;quot;/blog/2026/0108_gouvernance_agent_opencode_eager_lazy_post.html&amp;quot;&amp;gt;AsciiDocを使ってAIエージェントを管理する&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;条項 0110 — ホット/ウォーム/コールド メカニズム :&amp;lt;a href=&amp;quot;/blog/2026/0110_mecanisme_backup_contexte_agent_post.html&amp;quot;&amp;gt;スライディングウィンドウと寒波&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;私のサイト：https://cheroliv.com&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;プロジェクト`magic-stick`: &amp;lt;a href=&amp;quot;https://github.com/cheroliv/magic-stick&amp;quot; class=&amp;quot;bare&amp;quot;&amp;gt;https://github.com/cheroliv/magic-stick&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;hr&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;知識は消える必要はない。必要でないときはロードしないだけだ。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;</description>
        </item><item>
            <title>スライドウィンドウと寒波 : エージェントコンテキストが爆発し、損失なくアーカイブしなければならないとき</title>
            <link >https://cheroliv.com/blog/2026/0110_mecanisme_backup_contexte_agent_post.html</link>
            <pubDate>Sun, 26 Apr 2026 00:00:00 +0000</pubDate>
            <guid isPermaLink="false">blog/2026/0110_mecanisme_backup_contexte_agent_post.html</guid>
            <description>&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_要約&amp;quot;&amp;gt;要約&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;1つのプロジェクトで48セッション、合計で150以上を経て、私が細心の注意を払って構築したEager/Lazyガバナンスシステムは息詰まり始めていた。軽いものであるはずのエージェントファイルは、合計で5200行に膨れ上がっていた。自動的にロードされるコンテキストは、私が制御できる速度よりも速く増えていった。この記事では、スライディングウィンドウと同じようなコールドウェーブの間にあるバックアップメカニズムをどのように考案したかを説明し、決して何も失うことなく軽量なアクティブコンテキストを維持する方法について述べている。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_信号_5200_行&amp;quot;&amp;gt;信号 : 5200 行&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;私はセッション048の途中ですについて`magic-stick`, 私のLinuxライブISOビルドプロジェクト。Opencodeが私を見ている。いつものように、彼はセッションの開始時に私のEagerファイルを自動的にロードした—&amp;lt;code&amp;gt;AGENT.adoc&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;PROMPT_REPRISE.adoc&amp;lt;/code&amp;gt;, `.agents/INDEX.adoc`異常はありません。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;ただし、何かがおかしい。返答が遅くなる。推論が薄まる。エージェントは、2つ前のメッセージで目にしていた詳細を忘れてしまう。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;ターミナルを開いて、入力します :&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;wc -l .agents/INDEX.adoc .agents/SESSIONS_HISTORY.adoc \
  .agents/archives/COMPLETED_TASKS_ARCHIVE_2026-04.adoc&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;INDEX に 260 行。SESSIONS_HISTORY に 55 行。&amp;lt;strong&amp;gt;COMPLETED_TASKS_ARCHIVE用の1756&amp;lt;/strong&amp;gt;。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;フォルダー`sessions/`さらに約3200行を追加します。合計：&amp;lt;strong&amp;gt;5200行&amp;lt;/strong&amp;gt;コンテキストが読み込まれ、何らかの形でエージェントの一時的な脳内に存在する。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;私が前の記事で理論化したEager/Lazy戦略は機能する — しかし、私が予期していなかった生まれつきの欠陥がある：それは持っていない&amp;lt;strong&amp;gt;老化のメカニズムはありません&amp;lt;/strong&amp;gt;. 各セッションは、INDEXに1行を追加し、COMPLETED_TASKSに1段落を追加し、sessions/にファイルを追加します。何も出力されません。コンテキストは、新しいセッションごとに大きくなる雪だるまです。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div id=&amp;quot;diag-growth&amp;quot; class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
skinparam backgroundColor #FEFEFE
skinparam handwritten false

title コンテキストエージェントの成長 — セッション 1 から 48
rectangle &amp;quot;セッション 1-10&amp;quot; as S10 #E8F5E9
rectangle &amp;quot;セッション 11-20&amp;quot; as S20 #C8E6C9
rectangle &amp;quot;セッション 21-30&amp;quot; as S30 #A5D6A7
rectangle &amp;quot;セッション 31-40&amp;quot; as S40 #81C784
rectangle &amp;quot;セッション 41-48&amp;quot; as S48 #66BB6A

note right of S10
  INDEX : ~50 lignes
  SESSIONS : ~10 lignes
  ARCHIVE : ~100 lignes
  **Total : ~300 lignes**
end note

note right of S20
  INDEX : ~100 lignes
  SESSIONS : ~20 lignes
  ARCHIVE : ~400 lignes
  **Total : ~800 lignes**
end note

note right of S30
  INDEX : ~160 lignes
  SESSIONS : ~30 lignes
  ARCHIVE : ~900 lignes
  **Total : ~1800 lignes**
end note

note right of S40
  INDEX : ~220 lignes
  SESSIONS : ~45 lignes
  ARCHIVE : ~1400 lignes
  **Total : ~3200 lignes**
end note

note right of S48
  INDEX : **260 lignes**
  SESSIONS : **55 lignes**
  ARCHIVE : **1756 lignes**
  **Total : 5200 lignes** ⚠️
end note

S10 -[#green]-&amp;amp;gt; S20
S20 -[#green]-&amp;amp;gt; S30
S30 -[#FF9800]-&amp;amp;gt; S40
S40 -[#red]-&amp;amp;gt; S48

@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;これはバグではなく、セッション終了の手順が各ディテールを細部まで忠実にアーカイブする直接の結果です。システムは自身の成功の犠牲者です。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_診断トリプル冗長&amp;quot;&amp;gt;�診断：トリプル冗長&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;私はエージェントに問題を診断してもらうように依頼します。その返答は即座かつ的確です。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;table class=&amp;quot;tableblock frame-all grid-all stretch&amp;quot;&amp;gt;
&amp;lt;colgroup&amp;gt;
&amp;lt;col style=&amp;quot;width: 5%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 5%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 5%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 5%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 5%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 5%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 5%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 5%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 5%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 5%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 5%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 5%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 5%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 5%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 5%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 5%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 5%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 5%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 5%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 5%;&amp;quot;&amp;gt;
&amp;lt;/colgroup&amp;gt;
&amp;lt;tbody&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;ファイル&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;行&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;役割&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;問題&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;code&amp;gt;.agents/INDEX.adoc&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;260+&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;EAGER (自動充電)&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;001 からのすべてのセッションのテーブル —&amp;lt;strong&amp;gt;+1行/セッション&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;code&amp;gt;.agents/SESSIONS_HISTORY.adoc&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;55&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;熱意がある&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;サマリー表 —&amp;lt;strong&amp;gt;INDEXとの冗長性&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;code&amp;gt;COMPLETED_TASKS_ARCHIVE_2026-04.adoc&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;1756&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;EAGER(暗黙的)&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;4月のすべてのセッションの詳細&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;code&amp;gt;.agents/sessions/*.adoc&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;~5200 total&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;怠惰（そうとされる）&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;個人のアーカイブ、しかし&amp;lt;strong&amp;gt;使用されていない&amp;lt;/strong&amp;gt;なぜならすべてが既に COMPLETED_TASKS にあるから&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/tbody&amp;gt;
&amp;lt;/table&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;エージェントは4つの根本原因を特定します：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;olist arabic&amp;quot;&amp;gt;
&amp;lt;ol class=&amp;quot;arabic&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;COMPLETED_TASKS_ARCHIVEはすべてを吸収します&amp;lt;/strong&amp;gt;— アーカイブを指す代わりに`.sessions/`、彼は各セッションを完全にコピーします。&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;INDEX.adoc は完全な歴史として機能します&amp;lt;/strong&amp;gt;— 「Sessions Récentes」テーブルには30+件のエントリがあります。&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;SESSIONS_HISTORY.adocは冗長です&amp;lt;/strong&amp;gt;— INDEXと同じ情報、フォーマットが異なります。&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;LAZYルールは守られていません。&amp;lt;/strong&amp;gt;— COMPLETED_TASKS は暗黙のうちに EAGER です。なぜなら、すべてを含んでいるからです。&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ol&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;彼の提案は過激である：INDEXを10セッションに制限し、COMPLETED_TASKSを空にし、SESSIONS_HISTORYを純粋なLAZYに移動する。即時の利益：&amp;lt;strong&amp;gt;約1900行節約&amp;lt;/strong&amp;gt;。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;きれいで、効率的で、論理的です。でも、このアプローチに問題があります。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_なぜ私は明らかな解決策を断ったのか&amp;quot;&amp;gt;なぜ私は明らかな解決策を断ったのか&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;エージェントの解決策は、キャッシュを最適化するエンジニアのものです。制限。切り詰め。冗長削除。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;しかし、これらの「冗長性」ではありません。各ガバナンスファイルは 1 つを捉える&amp;lt;strong&amp;gt;異なる角度&amp;lt;/strong&amp;gt;同じ現実上で :&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;索引&amp;lt;/strong&amp;gt;= マクロビュー、エグゼクティブダッシュボード&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;セッション履歴&amp;lt;/strong&amp;gt;= 線形の年代順の表、スコア付き&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;COMPLETED_TASKS_ARCHIVE&amp;lt;/strong&amp;gt;= 詳細なナラティブとメトリクス&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;sessions/*.adoc&amp;lt;/strong&amp;gt; = 個々のアーカイブ、完全なコンテキスト&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;これは愚かな複製ではありません。これは&amp;lt;strong&amp;gt;複数の構造化された視点&amp;lt;/strong&amp;gt;. これは、蒸留するためにまさに必要なものです。そうすれば、後で人間（またはより訓練された将来のLLM）が角度をクロスし、パターンを抽出できるようになります。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;データサイエンティストが言うのを想像してください：「6つの列のうち3つを削除しましょう、それらは相関しています。」あなたは彼に何と答えますか？ 相関は、各列が同じ現象の異なる次元を捉えているときは冗長ではないということです。まさにこの多次元的な豊かさがデータセットを使えるようにしているのです。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;それが私の直感です。そして、私はそれをエージェントの冷たい理性に対して守っています。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;em&amp;gt;&amp;lt;em&amp;gt;_ 私の考えの中に、黙ってすべてを詰め込むようなものは見当たりません。私たちは全部を詰め込むのではなく、セッション終了手続きの構造化された結果を移動します — 各ファイルがその角度と、実際には豊かさである冗長性を持っています。この多次元的な材料こそが、蒸留に最適でしょう。 &amp;lt;/em&amp;gt;_&amp;lt;/em&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;エージェントは打撃を受ける。そして自分を正す。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_提案同じ寒波&amp;quot;&amp;gt;提案：同じ寒波&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;エージェントはその後、豊富なデータセットという私の直感を尊重しつつ、コンテキストが爆発するという技術的な問題を解決する、より細やかなメカニズムを提案します。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;原理はシンプルで、パターンから直接インスピレーションを得ています&amp;lt;strong&amp;gt;ホット/ウォーム/コールド ストレージ&amp;lt;/strong&amp;gt;アーカイブ管理に適用される :&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;熱い (EAGER)&amp;lt;/strong&amp;gt;= INDEX内の最後の10セッション, セッションN+1のPROMPT_REPRISE, 最後の2つのセッションファイル&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;温かい (LAZY)&amp;lt;/strong&amp;gt;= SESSIONS_HISTORY 最近, SCRIPT_VERIFICATION, すべてのリファレンスドキュメント&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;寒い (backup/)&amp;lt;/strong&amp;gt;= その他すべて、移動済み&amp;lt;strong&amp;gt;無傷の&amp;lt;/strong&amp;gt;, 変換なし、再インデックスなし&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-none hljs&amp;quot;&amp;gt;----
----
.agents/
├── INDEX.adoc                         → Sessions N-9 à N (10 dernières)
├── SESSIONS_HISTORY.adoc              → Sessions N-9 à N
├── SCRIPT_VERIFICATION.adoc           → Dernière vérif (pas d&amp;#39;historique)
├── PROMPT_REPRISE.adoc                → Session N+1 uniquement
├── sessions/                          → Sessions N-1 à N uniquement
└── backup/
    └── Y2026-sessions-001-039/          ← Vague froide, COPIE INTÉGRALE
        ├── INDEX.adoc                  → Sessions 001 à 039 (complet)
        ├── SESSIONS_HISTORY.adoc       → Sessions 001 à 039 (complet)
        ├── COMPLETED_TASKS_ARCHIVE.adoc → Sessions 001 à 039 (complet)
        └── sessions/                   → 001.adoc, 002.adoc...
----

メカニズムの鍵 :**バックアップは中央のインデックスではなく、過去の波の正確なコピーです。**. 10セッションのアクティブなホライゾンを超えると、何も削除せず、何も再インデックスせず、何もマージせず、セッション N-10時点のエージェントファイルのパケットをそのまま取り、それを移動`backup/`。

アクティブなファイルは、切り捨てられます :

* INDEX : 最後の10行のみ (sliding window)
* SESSIONS_HISTORY : 同様
* COMPLETED_TASKS_ARCHIVE : 現在の期間の新しいファイル
* sessions/ : 直近の 2 セッションのみ

[plantuml, format=svg, id=diag-hot-warm-cold, alt=&amp;quot;Architecture Hot/Warm/Cold du contexte agent — EAGER/LAZY/backup&amp;quot;]
----
@startuml
skinparam backgroundColor #FEFEFE
skinparam defaultTextAlignment center
skinparam wrapWidth 200

title コンテキスト エージェントのホット / ウォーム / コールド アーキテクチャ
package &amp;quot;HOT (EAGER)
自動的に充電
~300 行&amp;quot; as HOT #FFCDD2 {
  file &amp;quot;INDEX.adoc
(10 セッション)&amp;quot; as IDX_HOT
  file &amp;quot;PROMPT_REPRISE
(セッション N+1)&amp;quot; as PRO_HOT
  file &amp;quot;AGENT.adoc\n(絶対ルール)&amp;quot; as AG_HOT
}

package &amp;quot;WARM (LAZY)
オンデマンドでロード
約500行&amp;quot; as WARM #FFF9C4 {
  file &amp;quot;SESSIONS_HISTORY\n(最近の10件)&amp;quot; as HIS_WARM
  file &amp;quot;SCRIPT_VERIFICATION
(最後)&amp;quot; as VER_WARM
  file &amp;quot;PROCEDURES.adoc
(テンプレート)&amp;quot; as PRO_WARM
  file &amp;quot;*_REFERENCE.adoc
(技術文書)&amp;quot; as REF_WARM
}

package &amp;quot;COLD (backup/)
決して充電されていない
人間のみが読むことができます&amp;quot; as COLD #BBDEFB {
  folder &amp;quot;Y2026-001-039/&amp;quot; as WAVE {
    file &amp;quot;インデックス (完全)&amp;quot; as IDX_COLD
    file &amp;quot;SESSIONS_HISTORY\n(完了)&amp;quot; as HIS_COLD
    file &amp;quot;完了タスク
(完了)&amp;quot; as ARCH_COLD
    folder &amp;quot;セッション/ (001-039)&amp;quot; as SESS_COLD
  }
  folder &amp;quot;Y2026-040-???\n(将来)&amp;quot; as FUTURE
}

HOT --&amp;amp;gt; WARM : &amp;quot;エージェントが上がる
必要に応じて&amp;quot;
WARM --&amp;amp;gt; COLD : &amp;quot;決して自動ではない
人間は一人でそこに行く&amp;quot;

note bottom of COLD
  Règle : COPIE INTÉGRALE
  Pas de transformation
  Pas de réindexation
  Read-only après archivage
end note

@enduml
----

即時の利益は巨大です：EAGERコンテキストはから**~5200行から~300行まで**. 17で割る。 歴史的データの一行も失わずに。

== なぜこれは万能ではない

エージェントは、最初のイテレーションで、恐れていた`backup/`ブラックボックスになる — つまり、二度と見返すことのないファイルを捨て込むフォルダーだ。それは正当な恐れだ。だが、それは誤解に基づいている。

雑多な集まりとは、ファイルを投げ込むときのこと**構造もなく、慣習もなく、グループ化の論理もなく**. ここで、バックアップは期間 (Y2026-001-039) によって構造化されており、各バックアップフォルダには**同じ構造**が ファイル`.agents/`アクティブ : INDEX, SESSIONS_HISTORY, COMPLETED_TASKS_ARCHIVE, sessions/.

これは雑多なものではありません。これは**タイムスタンプ付きスナップショット**. さらに言うと、これは簡略化されたバージョン管理のメカニズムと言えるかもしれません — ただし、ファイルを個別にバージョン管理するのではなく、ある時点Tでのガバナンスの完全なパッケージをバージョン管理するという意味です。

古い情報を見つけたいときは、中央のインデックスは必要ありません。二つの選択肢があります。

1. **grep` ターゲット指定の** : `grep -r &amp;quot;zsh&amp;quot; backup/Y2026-001-039/`— そして、期間中にzshを言及するすべてを見つけることができます。どの角度からでも (INDEX, SESSIONS_HISTORY, セッションアーカイブ)。
2. **手動再統合**バックアップフォルダーを一時的にアクティブコンテキストにコピーし、エージェントにこの特定の期間を分析させるように依頼します。

インデックスは暗黙的である。ファイルの構造そのものに存在し— 各ファイルはそれ自身の視点からすでにインデックスである。

== 棚のメタファー

メカニズムを直感的にするために、私はそれを3つの棚に概念化しました

* **棚 1 (EAGER)**— 作業計画。私が必要としているもの *今*。最近のINDEX、PROMPT_REPRISE、絶対ルール。軽量、即時、重要。
* **棚 2 (LAZY)**— 参照図書館。私が要請時に取りに行けるもの。技術参照、最近の履歴、手順。ボリュームは大きいが、メモリにロードされていない。
* **�洞窟 (backup/)**— コールドアーカイブ。 過去のすべてだが、捨てたくないもの。 エージェントはそこに決して入らない。 人間は、蒸留したいときにそこに降りる。

エージェントは最初に4番目の棚を提案した — 一つ`index-backup.adoc`それは LAZY で、バックアップ全体の目次を含むものになるでしょう。私は断りました。それは、すでに線形成長に苦しんでいるシステムにさらなる冗長性を加えることになります。アーカイブされたファイルの構造はすでにインデックスです。

== 二重トリガーセンサー

概念化は堅固だったが、盲点が残っていた :**正確にいつ回転を開始するべきですか？**最初の記事はそれをオープンな質問として特定していた。二日後、答えは6つのプロジェクトのガバナンスファイルにコード化されていた：2つのトリガーを持つセンサー。

=== 自動トリガー — `N % 10 == 0

最初のトリガーは数学的なものです。セッション番号が10の倍数 — つまりセッション10、20、30、40 — のとき、バックアップのローテーションはセッション終了手順の一部として自動的に実行され、特に手順6の直後に実行されます。

なぜ10なのか？それは相反する二つの力の間の妥協点です。短すぎるウィンドウ（5セッション）は継続に必要な文脈を失い、長すぎるウィンドウ（20セッション）は文脈の肥大化問題を解決しません。1日あたり1～2セッションのペースで10セッションは概ね1週間分の仕事をカバーします。これはエージェントが最近の決定を思い出すには十分ですが、文脈が爆発的に増えるほどではありません。

=== しきい値トリガー — 500行 EAGER

2番目のトリガーは動的です。セッション番号に関わらず、累積されたEAGERファイルが超える場合**500行**, 回転が開始されます。

このしきい値は、セッションが例外的に生産的であるシナリオ — 少ないセッションで多くのコンテンツが書かれる — から保護します。120行の編集コンテンツを生成するセッションは、2行を修正するデバッグセッションよりもCOMPLETED_TASKS_ARCHIVEをはるかに速く肥大化させます。500行のしきい値は、経由で測定されます`wc -l .agents/INDEX.adoc .agents/archives/COMPLETED_TASKS_ARCHIVE_*.adoc PROMPT_REPRISE.adoc`, この非対称性を捉える。

=== マニュアルトリガー — &amp;quot;ローテーションバックアップ

最後に、人間が主導権を握ります。キーワード`rotation backup`, `backup rotation` ou `lance la rotation backup`要求時にプロシージャを起動し、セッションの終了とは独立して行われます。コンテキストが重くなってきたと感じたとき、まだ10の倍数には達していない場合や、新しい作業フェーズを開始する前に現在の作業フェーズをアーカイブしたいときに便利です。

[plantuml, format=svg, id=diag-capteur-trigger, alt=&amp;quot;Les trois déclencheurs du capteur de rotation backup — automatique, seuil, manuel&amp;quot;]
----
@startuml
skinparam backgroundColor #FEFEFE
skinparam defaultTextAlignment center
skinparam wrapWidth 200

title バックアップ回転センサー — 三つのトリガー
start

:Procédure de fin de session;
note right: Mots-clés &amp;quot;セッションの終了&amp;quot;\nou &amp;quot;ここでやめよう&amp;quot;

:Étapes 1 à 6\n(archivage standard);
note right
  1. Archive sessions/N.adoc
  2. MAJ PROMPT_REPRISE
  3. MAJ SESSIONS_HISTORY
  4. MAJ INDEX.adoc
  5. MAJ TEST_COVERAGE
  6. MAJ COMPLETED_TASKS
end note

if (N % 10 == 0\nOU\nEAGER cumulé &amp;amp;gt; 500 lignes ?) then (oui)
  :⚙️ Rotation Backup\n(étape 7);
  note right
    1. Créer backup/Y20XX-sessions-X-Y/
    2. Copier intégrale INDEX + HISTORY
       + COMPLETED_TASKS + sessions/
    3. Tronquer actifs à 10 sessions
    4. Ajouter _Localisation active_
  end note
else (non)
  :Pas de rotation;
endif

:Checklist [✅] x 7\n(si applicable);

stop

@enduml
----

この図は、セッション終了手順におけるセンサーの正確な挿入を示しています。ステップ 7 はオプションであり（２つの条件のいずれかが真である場合にのみ実行されます）が、常に *チェック* されます。最終チェックリストには`[✅] 7. Backup roté (si applicable)`。

=== 閉じられたループ

このセンサーは、前の記事で開かれたループを閉じます。Eager/Lazy ガバナンスは、2 つのセッション間のエージェント メモリの問題を解決しました。Hot/Warm/Cold メカニズムは、増大するメモリの問題を解決しました。2 つのトリガーを持つセンサーは、*いつ* の問題を解決します —  — 人間にコンテキスト サイズを監視する精神的負担を強いることなく。

[plantuml, format=svg, id=diag-boucle-fermee, alt=&amp;quot;Les trois couches de la gouvernance agent — Eager/Lazy, Hot/Warm/Cold, Capteur&amp;quot;]
----
@startuml
skinparam backgroundColor #FEFEFE
skinparam defaultTextAlignment center

title エージェントガバナンスの三層
left to right direction

package &amp;quot;�層 1 — メモリ
(条項 0108)&amp;quot; as C1 #E8F5E9 {
  rectangle &amp;quot;EAGER
ダッシュボード
自動ロード&amp;quot; as EAG
  rectangle &amp;quot;**LAZY**\n所有者マニュアル\n必要時にロード&amp;quot; as LAZ
  EAG -[hidden]right-&amp;amp;gt; LAZ
}

package &amp;quot;�層2 — 経年変化
(条項 0110)&amp;quot; as C2 #FFF9C4 {
  rectangle &amp;quot;**HOT**
10件のアクティブなセッション
~300 行&amp;quot; as HOT
  rectangle &amp;quot;**WARM**\n参照\n手順&amp;quot; as WRM
  rectangle &amp;quot;**COLD**
backup/
寒波&amp;quot; as CLD
  HOT -[hidden]right-&amp;amp;gt; WRM
  WRM -[hidden]right-&amp;amp;gt; CLD
}

package &amp;quot;レイヤー 3 — トリガー
(今日)&amp;quot; as C3 #BBDEFB {
  rectangle &amp;quot;**オート**\nN % 10 == 0&amp;quot; as AUTO
  rectangle &amp;quot;しきい値
&amp;amp;gt; 500行&amp;quot; as SEUIL
  rectangle &amp;quot;**マニュアル**
ローテーション バックアップ&amp;quot; as MAN
  AUTO -[hidden]right-&amp;amp;gt; SEUIL
  SEUIL -[hidden]right-&amp;amp;gt; MAN
}

C1 --&amp;amp;gt; C2 : &amp;quot;メモリは増大する
→ メカニズムが必要
老化の&amp;quot;
C2 --&amp;amp;gt; C3 : &amp;quot;老化
→ トリガーが必要です
これを実行するために&amp;quot;

note bottom of C3
  ✅ Déployé sur 6 projets
  magic-stick · bakery-gradle
  plantuml-gradle · cheroliv.com
  jhipster-gradle-plugins
  quizz-benchmark-gradle
end note

@enduml
----

3つの層は論理的に積み重なります。最初の層はエージェントにメモリを与えます。2番目の層はこのメモリがエージェントを圧迫しないようにします。3番目の層はこのメモリのメンテナンスを自動化し、人間がそれについて考える必要がなくなります。

=== cheroliv.comでの効果的な移行

メカニズムは理論のままでは残らなかった。 Sur`cheroliv.com`,最初のバックアップローテーションは2026年4月29日に実行されました — セッション-6から2までが移行されました`.agents/backup/Y2026-sessions-neg6-a-002/` :

|===
|ファイル |回転前 |回転後 |利益 |`.agents/INDEX.adoc` |リストされている19のセッション |10 セッション (3-12) |-9 件 |`.agents/SESSIONS_HISTORY.adoc` |18セッション |10セッション |-8件 |`COMPLETED_TASKS_ARCHIVE` |161 行 (セッション 1-12) |135 行 (セッション 3-12) |-26 行 |`sessions/` |20個のファイル |10ファイル |-10 ファイル |**バックアップ/** |存在しない |1つの寒波 (10件のアーカイブされたセッション) |+1 冷却パック
|===

行数の増加は控えめでした — プロジェクトは若く、12セッション — しかし重要なのは**メカニズムは整っている**. 次の自動ローテーションは、セッション20でトリガーされます。または、500行のEAGERに到達した場合はそれより早くトリガーされます。

== 人間エージェントのレッスン

このセッション048 から、AI エージェントとの協力について根本的に重要なことを学びました。

エージェントは自然なバイアスを持っている：それを求める**最適化する**, à **簡素化する**, à **�冗長を排除する**. これは、きれいで簡潔な回答を生成するように訓練されたシステムのバイアスです。リッチで多次元的なデータセットに直面したとき、その最初の反応はそれを最もシンプルな形にまで簡素化することです。

人間は、むしろ異なる直感を持っている：彼は構造化された冗長さが何かであると直感している**強み**, 欠点ではない。同じ現実に対する角度の多様性こそが、後に質の高い蒸留を可能にするものだ。

エージェントが間違っているわけではない。彼の `optimum` が私のものではないということだ。エージェントは…のために最適化している**プレゼント**直近の文脈、質問に対する素早い回答。人間はそれに最適化する**未来**— 3か月または3年で見つけ、交差し、蒸留する能力。

____ 私が欲しいのは未加工の素材だ。君の考え、ためらい、私の質問への答え。君のまとめではない。まとめは、私なら君より上手にできる。私が欲しいのは原材料だ。 ____

私がセッションの終わりに彼に言ったこの言葉は、すべてを表している。エージェントは生産のためのツールだ。人間は抽出のためのツールだ。ガバナンスはエージェントが自分一人で全てを理解できるように作られているわけではない — ガバナンスは、人間が後で生産された素材を扱えるように作られている。

同じ冷たい波は、この哲学の建築的な翻訳である：何も捨てず、何も結合せず、何も再インデックスしない。パケットをそのまま移動させる。蒸留は後に、手作業で、人間によって行われる。

== 前の記事の論理的な続き

もしあなたが読んだらlink:/blog/2026/0108_gouvernance_agent_opencode_eager_lazy_post.html[Eager/Lazy 戦略に関する記事], あなたは自然な進行を認識するでしょう:

1. **第108条**— Eager/Lazyガバナンス： *comment*エージェントコンテキストを2段階の可用性で構造化する方法
2. **この記事 0110**— バックアップメカニズム : *comment* このコンテキストを失うことなく古くする、それが大きすぎるようになるとき

最初の記事は次の質問に答えていた：「エージェントはセッション間で何も覚えていない。どうすれば記憶を与えることができるか？」

これは最初の質問から必然的に派生する質問に答えるものです：「メモリは各セッションごとに肥大化します。エージェントを削除せずに窒息させないようにするにはどうすればよいでしょうか？」

答えは1つのパターンに収まる：**ホット/ワーム/コールド**, ガバナンスファイルに適用された。そして一つの原則 :**決して何も失わない、常にすべてを再配置する**。

== リンク

* 前の記事 :link:/blog/2026/0108_gouvernance_agent_opencode_eager_lazy_post.html[AsciiDocを使ったAIエージェントの管理]
* 私のサイト : https://cheroliv.com
* プロジェクト`magic-stick`: https://github.com/cheroliv/magic-stick

---

*良いガバナンスシステムはデータを決して削除せず、整理する。*
----&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;</description>
        </item><item>
            <title>Gradle 9、Docker 29、Testcontainersがいら立つとき：JHipsterビルドのデバッグ</title>
            <link >https://cheroliv.com/blog/2026/0109_gradle_jhipster_docker_testcontainers_debugging_post.html</link>
            <pubDate>Sat, 25 Apr 2026 00:00:00 +0000</pubDate>
            <guid isPermaLink="false">blog/2026/0109_gradle_jhipster_docker_testcontainers_debugging_post.html</guid>
            <description>&amp;lt;div id=&amp;quot;toc&amp;quot; class=&amp;quot;toc&amp;quot;&amp;gt;
&amp;lt;div id=&amp;quot;toctitle&amp;quot;&amp;gt;Table des matières&amp;lt;/div&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel1&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_シーンjhipsterプロジェクトロードされなくなったビルド&amp;quot;&amp;gt;シーン：JHipsterプロジェクト、ロードされなくなったビルド&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_エラー_1_ファントム変数_reportsdir&amp;quot;&amp;gt;エラー 1: ファントム変数 `reportsDir&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_エラー_2_main_は_gradle_9_で存在しなくなりました&amp;quot;&amp;gt;エラー 2 : &amp;lt;code&amp;gt;main = \&amp;quot;&amp;amp;#8230;&amp;amp;#8203;\&amp;quot;&amp;lt;/code&amp;gt; は Gradle 9 で存在しなくなりました&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_エラー_3_sourcecompatibility_はもはやプロジェクトのプロパティではありません&amp;quot;&amp;gt;エラー 3 : &amp;lt;code&amp;gt;sourceCompatibility&amp;lt;/code&amp;gt; はもはやプロジェクトのプロパティではありません&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_エラー_4_3項演算子の_groovy_アサーション&amp;quot;&amp;gt;エラー 4 : 3項演算子の Groovy アサーション&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_エラー_5_暗黙の依存_compilekotlin_openapigenerate&amp;quot;&amp;gt;エラー 5 : 暗黙の依存 &amp;lt;code&amp;gt;compileKotlin&amp;lt;/code&amp;gt; → `openApiGenerate&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_エラー_6_generategitproperties_で壊れる_filteroutputstream_write&amp;quot;&amp;gt;エラー 6 : &amp;lt;code&amp;gt;generateGitProperties&amp;lt;/code&amp;gt; で壊れる `FilterOutputStream.write()&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_最後にtestcontainersが舞台に登場&amp;quot;&amp;gt;最後に：Testcontainersが舞台に登場&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_phase_1_docker_javaのトラック&amp;quot;&amp;gt;Phase 1 : docker-javaのトラック&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_phase_2_ウェブ検索とgithubのパンくずリスト&amp;quot;&amp;gt;Phase 2: ウェブ検索とGitHubのパンくずリスト&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_フェーズ3_リネームされたアーティファクトの罠&amp;quot;&amp;gt;フェーズ3 : リネームされたアーティファクトの罠&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_フェーズ4解決を強制する&amp;quot;&amp;gt;フェーズ4：解決を強制する&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_最終結果&amp;quot;&amp;gt;最終結果&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_修正のサマリーテーブル&amp;quot;&amp;gt;修正のサマリーテーブル&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_結論&amp;quot;&amp;gt;結論&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div id=&amp;quot;preamble&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;読了時間 : 15 minutes&amp;lt;/div&amp;gt;
&amp;lt;p&amp;gt;あなたは、シンプルな瞬間を経験したことがあります。`./gradlew build`1日100回も起動していると、突然、これまで見たことのないエラーでクラッシュするようになる？これを11回連続のエラーで掛け合わせ、Docker Engine 29の互換性不足をたっぷりと加え、10年使っていたAPIが消えてしまうGradle 9を振りかけると。これが完全なログです。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;hr&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;図 1 — Gradle 9 移行 (エラーチェーン)&amp;lt;/div&amp;gt;
&amp;lt;p&amp;gt;目的：不互換性のシリーズを示す。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;👉 明確で、Gradle を中心とした。&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
left to right direction
title Gradle 9 移行
rectangle &amp;quot;1
レポートディレクトリ&amp;quot; as A
rectangle &amp;quot;2
メインクラス&amp;quot; as B
rectangle &amp;quot;3
ソース互換性&amp;quot; as C
rectangle &amp;quot;4
Groovy アサート&amp;quot; as D

A --&amp;amp;gt; B
B --&amp;amp;gt; C
C --&amp;amp;gt; D

@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;hr&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;図 2 — 互換性のない JHipster プラグイン&amp;lt;/div&amp;gt;
&amp;lt;p&amp;gt;目的：壊れたプラグインを隔離する。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;👉 依存関係の明確なビジョン.&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
left to right direction
title 修正が必要なプラグイン
skinparam shadowing false
skinparam roundcorner 18

rectangle &amp;quot;1
openApiGenerate&amp;quot; as A #FFF3E0
rectangle &amp;quot;2\ngitProperties\n2.5.7&amp;quot; as B #FFF3E0
rectangle &amp;quot;3
バージョン
修正された&amp;quot; as C #E3F2FD
rectangle &amp;quot;4
組み立て OK&amp;quot; as D #E8F5E9

A --&amp;amp;gt; B
B --&amp;amp;gt; C
C --&amp;amp;gt; D

@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;hr&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;�図3 — Docker 29 / Testcontainers&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;目的 : 実行時問題。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;👉 ランタイムの明瞭な歴史&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
left to right direction
title Docker 29 + Testcontainers

skinparam shadowing false
skinparam roundcorner 18
skinparam defaultFontSize 14

rectangle &amp;quot;1\n組み立て OK&amp;quot; as A #E8F5E9
rectangle &amp;quot;2
テスト Cucumber 失敗&amp;quot; as B #FFEBEE
rectangle &amp;quot;3
Testcontainers 1.32
拒否された&amp;quot; as C #FFF3E0
rectangle &amp;quot;4
アップグレード
バージョン&amp;quot; as D #E3F2FD
rectangle &amp;quot;5
最終ビルド OK&amp;quot; as E #E8F5E9

A --&amp;amp;gt; B
B --&amp;amp;gt; C
C --&amp;amp;gt; D
D --&amp;amp;gt; E

@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;hr&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;もう一つの自分なりに表現する方法&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml

!option handwritten true

skinparam backgroundColor #FEFEFE
skinparam shadowing false
skinparam defaultFontName Inter
skinparam defaultFontSize 14
skinparam ArrowThickness 2
skinparam RoundCorner 18

title 安定化ロードマップ — Gradle 9 から最終ビルドまで
left to right direction

rectangle &amp;quot;⚙️ Gradle 9 への移行&amp;quot; as A #E3F2FD
rectangle &amp;quot;🧩 プラグイン JHipster&amp;quot; as B #FFF3E0
rectangle &amp;quot;�🐳 Docker 29
Testcontainers&amp;quot; as C #FCE4EC
rectangle &amp;quot;�✅ 安定ビルド&amp;quot; as D #E8F5E9

note bottom of A
reportsDir
mainClass
sourceCompatibility
Groovy assert
end note

note bottom of B
openApiGenerate
gitProperties
versions alignées
end note

note bottom of C
tests Cucumber KO
image Docker rejetée
upgrade libs
end note

A -[#42A5F5]-&amp;amp;gt; B : corrections build.gradle
B -[#FB8C00]-&amp;amp;gt; C : assemble OK
C -[#E53935]-&amp;amp;gt; D : tests réparés

@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_シーンjhipsterプロジェクトロードされなくなったビルド&amp;quot;&amp;gt;シーン：JHipsterプロジェクト、ロードされなくなったビルド&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;プロジェクト`edster`2024年に生成されたJHipsterアプリケーションです。ルートビルドスクリプト`build.gradle`数か月間、安定していた。それから、バージョンアップすることに決めた：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;table class=&amp;quot;tableblock frame-all grid-all stretch&amp;quot;&amp;gt;
&amp;lt;colgroup&amp;gt;
&amp;lt;col style=&amp;quot;width: 7.1428%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 7.1428%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 7.1428%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 7.1428%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 7.1428%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 7.1428%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 7.1428%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 7.1428%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 7.1428%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 7.1428%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 7.1428%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 7.1428%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 7.1428%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 7.1436%;&amp;quot;&amp;gt;
&amp;lt;/colgroup&amp;gt;
&amp;lt;tbody&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;コンポーネント&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;ターゲットバージョン&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;グラドル&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;9.4.1&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;ジャバ&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;21.0.11-tem (Eclipse Temurin)&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;JHipster&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;8.x (フレームワーク`tech.jhipster:jhipster-framework:8.11.0`)&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;スプリングブート&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;3.4.5&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;コトリン&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;2.3.0&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;Docker Engine&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;29.4.1 (API 1.54)&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/tbody&amp;gt;
&amp;lt;/table&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;Javaバージョンの変更はSDKMANを通じて行われます :&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;sdk use java 21.0.11-tem&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;初回起動 :&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;$ ./gradlew build --no-daemon

FAILURE: Build failed with an exception.

* Where:
Build file &amp;#39;/home/.../edster/build.gradle&amp;#39; line: 18

* What went wrong:
An exception occurred applying plugin request [id: &amp;#39;jhipster.cucumber-conventions&amp;#39;]
&amp;amp;gt; Failed to apply plugin &amp;#39;jhipster.cucumber-conventions&amp;#39;.
   &amp;amp;gt; Could not create task &amp;#39;:cucumberTest&amp;#39;.
      &amp;amp;gt; Could not create task &amp;#39;:consoleLauncherTest&amp;#39;.
         &amp;amp;gt; Could not set unknown property &amp;#39;reportsDir&amp;#39; for task &amp;#39;:consoleLauncherTest&amp;#39;&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;ビルドスクリプトのロードさえ行われず、問題は`buildSrc/src/main/groovy/jhipster.cucumber-conventions.gradle`.&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_エラー_1_ファントム変数_reportsdir&amp;quot;&amp;gt;エラー 1: ファントム変数 `reportsDir&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;スクリプト`jhipster.cucumber-conventions.gradle`含む：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-groovy hljs&amp;quot; data-lang=&amp;quot;groovy&amp;quot;&amp;gt;tasks.register(&amp;#39;consoleLauncherTest&amp;#39;, JavaExec) {
    dependsOn(testClasses)
    String cucumberReportsDir = file(&amp;quot;$buildDir/reports/tests&amp;quot;)
    outputs.dir(reportsDir)           // &amp;amp;lt;-- reportsDir n&amp;#39;existe PAS
    classpath = sourceSets[&amp;quot;test&amp;quot;].runtimeClasspath
    main = &amp;quot;org.junit.platform.console.ConsoleLauncher&amp;quot;
    // ...
}&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;定義された変数は`cucumberReportsDir`. 使用されているものは`reportsDir`-- どこにも定義されていない。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;修正&amp;lt;/strong&amp;gt;:`outputs.dir(cucumberReportsDir)`&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_エラー_2_main_は_gradle_9_で存在しなくなりました&amp;quot;&amp;gt;エラー 2 : &amp;lt;code&amp;gt;main = \&amp;quot;&amp;amp;#8230;&amp;amp;#8203;\&amp;quot;&amp;lt;/code&amp;gt; は Gradle 9 で存在しなくなりました&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;即時フォローアップ：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-none hljs&amp;quot;&amp;gt;Could not set unknown property &amp;#39;main&amp;#39; for task &amp;#39;:consoleLauncherTest&amp;#39; of type org.gradle.api.tasks.JavaExec.&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;Gradle 9はプロパティを削除します`main`の利益のために`mainClass`タスクについて`JavaExec`.&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;�訂正&amp;lt;/strong&amp;gt;:`mainClass = &amp;quot;org.junit.platform.console.ConsoleLauncher&amp;quot;`&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_エラー_3_sourcecompatibility_はもはやプロジェクトのプロパティではありません&amp;quot;&amp;gt;エラー 3 : &amp;lt;code&amp;gt;sourceCompatibility&amp;lt;/code&amp;gt; はもはやプロジェクトのプロパティではありません&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;新しいエラー：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-none hljs&amp;quot;&amp;gt;Could not set unknown property &amp;#39;sourceCompatibility&amp;#39; for root project &amp;#39;edster&amp;#39; of type org.gradle.api.Project.&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;ルートスクリプトは持っていた：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-groovy hljs&amp;quot; data-lang=&amp;quot;groovy&amp;quot;&amp;gt;sourceCompatibility=17
targetCompatibility=17&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;グラドル9はルートレベルでこれらのプロパティを削除します。これらのプロパティはブロック内に存在する必要があります。&amp;lt;code&amp;gt;java&amp;lt;/code&amp;gt;.&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;修正&amp;lt;/strong&amp;gt; :&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-groovy hljs&amp;quot; data-lang=&amp;quot;groovy&amp;quot;&amp;gt;java {
    sourceCompatibility = JavaVersion.VERSION_21
    targetCompatibility = JavaVersion.VERSION_21
}&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_エラー_4_3項演算子の_groovy_アサーション&amp;quot;&amp;gt;エラー 4 : 3項演算子の Groovy アサーション&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;古いスクリプトには:&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-groovy hljs&amp;quot; data-lang=&amp;quot;groovy&amp;quot;&amp;gt;assert System.properties[&amp;quot;java.specification.version&amp;quot;] == &amp;quot;17&amp;quot; || &amp;quot;21&amp;quot; || &amp;quot;24&amp;quot;&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;Groovyでは,&amp;lt;code&amp;gt;&amp;quot;21&amp;quot;&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;&amp;quot;24&amp;quot;`は strings truthy。 式は &amp;amp;#8230;&amp;amp;#8203; に解決されます&amp;lt;/code&amp;gt;(&amp;amp;#8230;&amp;amp;#8203; == &amp;quot;17&amp;quot;) || true || true`, これは常に真である&amp;amp;#8201;&amp;amp;#8212;&amp;amp;#8201;しかし、構文は望まれる厳密なアサーションには無効です。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;修正&amp;lt;/strong&amp;gt;:&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-groovy hljs&amp;quot; data-lang=&amp;quot;groovy&amp;quot;&amp;gt;assert System.properties[&amp;quot;java.specification.version&amp;quot;] in [&amp;quot;17&amp;quot;, &amp;quot;21&amp;quot;, &amp;quot;23&amp;quot;, &amp;quot;24&amp;quot;]&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_エラー_5_暗黙の依存_compilekotlin_openapigenerate&amp;quot;&amp;gt;エラー 5 : 暗黙の依存 &amp;lt;code&amp;gt;compileKotlin&amp;lt;/code&amp;gt; → `openApiGenerate&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;ビルドが進行しています。Kotlinのコンパイルに成功しました。その後：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-none hljs&amp;quot;&amp;gt;Task &amp;#39;:compileKotlin&amp;#39; uses this output of task &amp;#39;:openApiGenerate&amp;#39;
without declaring an explicit or implicit dependency.&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;Gradle 9 は暗黙的なタスク間の依存関係を拒否します。以来`compileKotlin`生成されたソースを読む`openApiGenerate`、リンクを宣言する必要がある。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;�訂正&amp;lt;/strong&amp;gt;中に`build.gradle`:&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-groovy hljs&amp;quot; data-lang=&amp;quot;groovy&amp;quot;&amp;gt;afterEvaluate {
    tasks.named(&amp;quot;compileKotlin&amp;quot;).configure {
        dependsOn(tasks.named(&amp;quot;openApiGenerate&amp;quot;))
    }
}&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;Le `afterEvaluate`必要です なぜなら`openApiGenerate`est une extension (plugin OpenAPI Generator) et non une tâche directement accessible pendant la phase de configuration. &amp;amp;#8594; Japanese translation:&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;これは OpenAPI Generator プラグインの拡張機能であり、構成フェーズにおいて直接アクセス可能なタスクではありません。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_エラー_6_generategitproperties_で壊れる_filteroutputstream_write&amp;quot;&amp;gt;エラー 6 : &amp;lt;code&amp;gt;generateGitProperties&amp;lt;/code&amp;gt; で壊れる `FilterOutputStream.write()&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;Javaのコンパイルが通ります。リソースが処理されます。次に：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-none hljs&amp;quot;&amp;gt;&amp;amp;gt; Task :generateGitProperties FAILED

No signature of method: java.io.FilterOutputStream.write() is applicable for argument types: (Integer) values: [103]&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;プラグイン`gradle-git-properties`version 2.5.0 は Java 21 / Gradle 9 と互換性がありません。内部バグが呼び出しを試みます`write(int)`Groovy経由でそれを閉じたストリーム上で&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;修正&amp;lt;/strong&amp;gt;中に`gradle.properties` :&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-properties hljs&amp;quot; data-lang=&amp;quot;properties&amp;quot;&amp;gt;gitPropertiesPluginVersion=2.5.7&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_最後にtestcontainersが舞台に登場&amp;quot;&amp;gt;最後に：Testcontainersが舞台に登場&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;今のところ、これは純粋な &amp;quot;build script debugging&amp;quot; でした。各エラーは、ビルドスクリプトにおけるGradle 9またはJava 21の互換性の問題でした。前述の6つの修正後、`./gradlew assemble`成功裏に通ります。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;しかし`./gradlew build`実行し、Cucumberのテストも Testcontainers を使って一時的な PostgreSQL を起動します。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-none hljs&amp;quot;&amp;gt;Could not find a valid Docker environment.

EnvironmentAndSystemPropertyClientProviderStrategy: failed with exception BadRequestException
(Status 400: {&amp;quot;message&amp;quot;:&amp;quot;client version 1.32 is too old. Minimum supported API version is 1.40&amp;quot;}
UnixSocketClientProviderStrategy: failed with exception BadRequestException
(Status 400: {&amp;quot;message&amp;quot;:&amp;quot;client version 1.32 is too old. Minimum supported API version is 1.40&amp;quot;}&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;TestcontainersはDockerと通信できません。異なる2つの戦略（環境変数＋Unixソケット）が同じエラーで失敗します。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div id=&amp;quot;diag-docker-handshake&amp;quot; class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
skinparam backgroundColor #FEFEFE
skinparam handwritten false

actor &amp;quot;Testcontainers
1.20.6&amp;quot; as TC
participant &amp;quot;docker-java
3.4.1&amp;quot; as DJ
participant &amp;quot;Docker Engine
29.4.1&amp;quot; as DE

TC -&amp;amp;gt; DJ : new DockerClient()
DJ -&amp;amp;gt; DE : GET /_ping\nUser-Agent: docker-java/3.4.1\nAPI-Version: 1.32
DE --&amp;amp;gt; DJ : HTTP 400 Bad Request\nclient version 1.32 is too old.\nMinimum supported API version is 1.40
DJ --&amp;amp;gt; TC : BadRequestException
TC --&amp;amp;gt; TC : Could not find a valid\nDocker environment

note right of DE
  Docker Engine 29.x impose
  API minimum = 1.40
  (défaut ancien : 1.24)
end note

note left of DJ
  docker-java 3.4.1 envoie
  hardcoded API version 1.32
  dans l&amp;#39;en-tête HTTP
end note

@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_phase_1_docker_javaのトラック&amp;quot;&amp;gt;Phase 1 : docker-javaのトラック&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;まず最初に、Testcontainers が使用する Docker Java クライアントは、API のバージョンを送信します。&amp;lt;code&amp;gt;1.32`そのHTTPハンドシェイクにおいてですが、Docker Engine 29.4.1は最低限`1.40&amp;lt;/code&amp;gt;. 問題はクライアント側にあり、デーモン側ではありません。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;Testcontainers 1.20.6 によって解決された docker-java のバージョンの確認 :&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;$ ./gradlew dependencies --configuration testRuntimeClasspath | grep docker-java

+--- com.github.docker-java:docker-java-api:3.4.1
+--- com.github.docker-java:docker-java-transport:3.4.1&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;docker-java 3.4.1（Testcontainers 1.20.6 から）。docker-java の最新のパブリックバージョンは 3.5.1 です。バージョンアップを強制するために`resolutionStrategy`ブロックの中`configurations` de &amp;lt;code&amp;gt;build.gradle&amp;lt;/code&amp;gt;:&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-groovy hljs&amp;quot; data-lang=&amp;quot;groovy&amp;quot;&amp;gt;configurations {
    all {
        resolutionStrategy.eachDependency { details -&amp;amp;gt;
            if (details.requested.group == &amp;quot;com.github.docker-java&amp;quot;
                &amp;amp;amp;&amp;amp;amp; details.requested.name.startsWith(&amp;quot;docker-java&amp;quot;)) {
                details.useVersion(&amp;quot;3.5.1&amp;quot;)
            }
        }
    }
}&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;ビルドの再起動。同じエラー：&amp;lt;code&amp;gt;client version 1.32 is too old&amp;lt;/code&amp;gt;。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;Gradleキャッシュの確認：JARsは正しく再ダウンロードされましたが、エラーは依然として残っています。docker-java 3.5.1 はまだ送信しています`1.32`. このバージョンはしたがって Docker Engine 29.4.1 に対して十分ではありません。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;�浄化のアクション&amp;lt;/strong&amp;gt;: Gradleキャッシュを完全にクリアして、念のため :&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;rm -rf ~/.gradle/caches
rm -rf /path/to/project/.gradle&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;パージ後に完全再起動。同じエラー。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_phase_2_ウェブ検索とgithubのパンくずリスト&amp;quot;&amp;gt;Phase 2: ウェブ検索とGitHubのパンくずリスト&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;docker-java 3.5.1 は不十分です。あとは、誰かがこの問題に正確に遭遇したかどうかを調べるだけです。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;testcontainers-java と docker-java の issue に対するターゲット検索:&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-none hljs&amp;quot;&amp;gt;site:github.com/testcontainers &amp;quot;client version 1.32 is too old&amp;quot;
site:github.com/docker-java &amp;quot;client version 1.32&amp;quot; Docker Engine 29&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;最初の即時の結果：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;https://github.com/testcontainers/testcontainers-java/issues/11210&amp;quot;&amp;gt;testcontainers-java#11210&amp;lt;/a&amp;gt;—&amp;lt;code&amp;gt;[Bug]: client version 1.32 is too old. Minimum supported API version is 1.44&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;https://github.com/testcontainers/testcontainers-java/issues/11212&amp;quot;&amp;gt;testcontainers-java#11212&amp;lt;/a&amp;gt;—&amp;lt;code&amp;gt;[Bug]: Docker 29.0.0 could not find a valid Docker environment&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;https://github.com/testcontainers/testcontainers-java/issues/11491&amp;quot;&amp;gt;testcontainers-java#11491&amp;lt;/a&amp;gt;—&amp;lt;code&amp;gt;[Bug]: Incompatibility in Ubuntu Github runners with Docker Engine 29.1.*&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;パンくずリストは明確です : Docker Engine 29.x は最低 API バージョンを`1.24`(古い欠陥) に`1.40`. Testcontainers 1.20.x は docker-java 3.4.x を使用し、API バージョンを送信してネゴシエートします。&amp;lt;code&amp;gt;1.32&amp;lt;/code&amp;gt;. デーモンは礼儀正しくしかし固く拒否します。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;issue #11491では、メンテナーが返信します:&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;em&amp;gt;&amp;lt;em&amp;gt;_ ハイ、バージョン2.0.3で動作しているプロジェクトをGHランナー上でエンジン29.1を使用して実行しており、正常に動作しています。 皆さん、バージョンの競合がないかどうか確認していただけますか？ お忘れなく、すべてのモジュールはプリフィックスが付いていました`testcontainers-&amp;lt;code&amp;gt;。 それで、バージョン2.xから始めて、私たちはから進んできた`postgresql&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;testcontainers-postgresql&amp;lt;/code&amp;gt; &amp;lt;/em&amp;gt;_&amp;lt;/em&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;この回答には&amp;lt;strong&amp;gt;重要な情報が2つ&amp;lt;/strong&amp;gt;&amp;amp;lt;/think&amp;amp;gt; &amp;amp;lt;/think&amp;amp;gt; (Note: Since no French text was provided after the colon, there is nothing to translate, so the output is empty.)&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;olist arabic&amp;quot;&amp;gt;
&amp;lt;ol class=&amp;quot;arabic&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;Testcontainers 2.0.3+ は問題を解決します&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;モジュールは&amp;lt;strong&amp;gt;プレフィックス `testcontainers-`を付けてリネームされます&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ol&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_フェーズ3_リネームされたアーティファクトの罠&amp;quot;&amp;gt;フェーズ3 : リネームされたアーティファクトの罠&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;名前の変更は厳しいです。Testcontainers 2.x では、以前の名前のいずれもその名前では機能しなくなりました：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;table class=&amp;quot;tableblock frame-all grid-all stretch&amp;quot;&amp;gt;
&amp;lt;colgroup&amp;gt;
&amp;lt;col style=&amp;quot;width: 10%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 10%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 10%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 10%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 10%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 10%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 10%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 10%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 10%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 10%;&amp;quot;&amp;gt;
&amp;lt;/colgroup&amp;gt;
&amp;lt;tbody&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;旧名 (1.x)&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;新しい名前 (2.x)&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;code&amp;gt;org.testcontainers:postgresql&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;code&amp;gt;org.testcontainers:testcontainers-postgresql&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;code&amp;gt;org.testcontainers:jdbc&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;code&amp;gt;org.testcontainers:testcontainers-jdbc&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;code&amp;gt;org.testcontainers:junit-jupiter&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;code&amp;gt;org.testcontainers:testcontainers-junit-jupiter&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;code&amp;gt;org.testcontainers:testcontainers&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;変更されていない&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/tbody&amp;gt;
&amp;lt;/table&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;最初の試み : Testcontainers BOM 2.0.5 と新しいアーティファクト名を適用する`build.gradle`。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-groovy hljs&amp;quot; data-lang=&amp;quot;groovy&amp;quot;&amp;gt;dependencies {
    testImplementation platform(&amp;quot;org.testcontainers:testcontainers-bom:2.0.5&amp;quot;)
    testImplementation &amp;quot;org.testcontainers:testcontainers-postgresql&amp;quot;
    testImplementation &amp;quot;org.testcontainers:testcontainers-jdbc&amp;quot;
    testImplementation &amp;quot;org.testcontainers:testcontainers-junit-jupiter&amp;quot;
    testImplementation &amp;quot;org.testcontainers:testcontainers&amp;quot;
}&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;code&amp;gt;./gradlew build&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-none hljs&amp;quot;&amp;gt;FAILURE: Could not find org.testcontainers:jdbc:2.0.5.
Could not find org.testcontainers:junit-jupiter:2.0.5.&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;testcontainers-bomのBOMだけでは十分ではありません。&amp;lt;/strong&amp;gt;なぜ？ Spring Boot 3.4.5は独自の依存関係管理BOMを公開しているため（&amp;lt;code&amp;gt;spring-boot-dependencies&amp;lt;/code&amp;gt;) 誰&amp;lt;strong&amp;gt;勝つ&amp;lt;/strong&amp;gt;TestcontainersのBOMの transitive 解決において。 Spring Bootは修正します。&amp;lt;code&amp;gt;testcontainers&amp;lt;/code&amp;gt; à &amp;lt;code&amp;gt;1.20.6&amp;lt;/code&amp;gt;, したがって、Spring Boot BOMに明示的に含まれていないすべてのアーティファクト（新しいものなど）は`testcontainers-*&amp;lt;code&amp;gt;) 彼らは古い名前に向かって解決する`1.20.6&amp;lt;/code&amp;gt;-- このバージョンでは存在しなくなりました。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;検査している際の`dependencies --configuration testRuntimeClasspath`, 見つかる :&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-none hljs&amp;quot;&amp;gt;+--- org.testcontainers:testcontainers -&amp;amp;gt; 1.20.6 (*)
|    \--- org.testcontainers:testcontainers:2.0.5 -&amp;amp;gt; 1.20.6&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;Le &amp;lt;code&amp;gt;&amp;amp;#8594;`置換を示します : Testcontainers 2.0.5 は &amp;lt;strong&amp;gt;要求されています&amp;lt;/strong&amp;gt;, しかし Spring Boot は強制します`1.20.6&amp;lt;/code&amp;gt;.&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div id=&amp;quot;diag-bom-war&amp;quot; class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
skinparam backgroundColor #FEFEFE
skinparam handwritten false
skinparam componentStyle rectangle

left to right direction

component &amp;quot;build.gradle
(消費者)&amp;quot; as BG #E3F2FD {
    rectangle &amp;quot;要求
`testcontainers-bom:2.0.5&amp;quot; as REQ
    rectangle &amp;quot;要求
`testcontainers-postgresql&amp;quot; as REQ2
}

component &amp;quot;Mavenセントラル&amp;quot; as MC #FFF3E0

component &amp;quot;声明&amp;quot; as DEC #E8F5E9 {
    rectangle &amp;quot;testcontainers-bom:2.0.5`
修正 2.0.5&amp;quot; as BOM2
    rectangle &amp;quot;spring-boot-dependencies:3.4.5`
修正 1.20.6&amp;quot; as BOM1
}

component &amp;quot;Gradle 解決&amp;quot; as RES #FFEBEE {
    rectangle &amp;quot;勝ち抜いたバージョン
`testcontainers:1.20.6&amp;quot; as WIN #EF9A9A
}

BG --&amp;amp;gt; DEC : &amp;quot;BOMsを分析する&amp;quot;
BOM2 --&amp;amp;gt; RES : &amp;quot;バージョン2.0.5を提案&amp;quot;
BOM1 --&amp;amp;gt; RES : &amp;quot;提案 1.20.6&amp;quot;
WIN -&amp;amp;gt; MC : &amp;quot;ダウンロード
testcontainers:1.20.6&amp;quot;

note bottom of WIN
  Spring Boot BOM prime car
  le plugin spring-boot applique
  ses dépendances de gestion
  après la résolution du consommateur
end note

@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_フェーズ4解決を強制する&amp;quot;&amp;gt;フェーズ4：解決を強制する&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;戦略は二重になります：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;olist arabic&amp;quot;&amp;gt;
&amp;lt;ol class=&amp;quot;arabic&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;docker-java のバージョンを 3.7.1 に固定する（Docker Engine 29 と互換性があるとテスト済み）&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;Spring BootのBOMを回避してTestcontainersコアを2.0.5に強制する&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ol&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div id=&amp;quot;diag-resolution-override&amp;quot; class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
skinparam backgroundColor #FEFEFE
skinparam handwritten false
skinparam componentStyle rectangle

left to right direction

component &amp;quot;build.gradle
(resolutionStrategyを使用して)&amp;quot; as BG #E8F5E9 {
    rectangle &amp;quot;BOM テストコンテナーズ
`2.0.5&amp;quot; as BOM2
    rectangle &amp;quot;resolutionStrategy\n.eachDependency&amp;quot; as RS #66BB6A
}

component &amp;quot;解決済み&amp;quot; as RESOLVED #E3F2FD {
    rectangle &amp;quot;docker-java
`3.7.1` (強制)&amp;quot; as DJ
    rectangle &amp;quot;testcontainers
`2.0.5` (強制)&amp;quot; as TC #81C784
    rectangle &amp;quot;testcontainers-postgresql
`2.0.5&amp;quot; as TPG
    rectangle &amp;quot;testcontainers-jdbc
`2.0.5&amp;quot; as TJ
    rectangle &amp;quot;testcontainers-junit-jupiter
`2.0.5&amp;quot; as TJJ
}

component &amp;quot;BOM Spring Boot
(暗黙の, オーバーライドされた)&amp;quot; as BOM1 #FFEBEE

component &amp;quot;マーベンセントラル&amp;quot; as MC #FFF3E0

BG --&amp;amp;gt; RESOLVED : &amp;quot;BOM Testcontainers 2.0.5
直接通ります&amp;quot;
RS -&amp;amp;gt; DJ : &amp;quot;力 3.7.1&amp;quot;
RS -&amp;amp;gt; TC : &amp;quot;力 2.0.5&amp;quot;
RESOLVED --&amp;amp;gt; MC : &amp;quot;JARsをダウンロード
Docker 29 と互換性がある&amp;quot;
BOM1 -[#gray,dashed]-&amp;amp;gt; RESOLVED : &amp;quot;testcontainersで無視された\nそして docker-java&amp;quot;

note bottom of RS
  Le `eachDependency` intercepte
  la résolution Gradle AVANT
  que le BOM Spring Boot ne gagne.
  C&amp;#39;est une intervention chirurgicale.
end note

@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;最終修正&amp;lt;/strong&amp;gt;中に`build.gradle`:&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-groovy hljs&amp;quot; data-lang=&amp;quot;groovy&amp;quot;&amp;gt;configurations {
    all {
        resolutionStrategy.eachDependency { details -&amp;amp;gt;
            if (details.requested.group == &amp;quot;com.github.docker-java&amp;quot;
                &amp;amp;amp;&amp;amp;amp; details.requested.name.startsWith(&amp;quot;docker-java&amp;quot;)) {
                details.useVersion(&amp;quot;3.7.1&amp;quot;)
            }
            if (details.requested.group == &amp;quot;org.testcontainers&amp;quot;
                &amp;amp;amp;&amp;amp;amp; details.requested.name == &amp;quot;testcontainers&amp;quot;) {
                details.useVersion(&amp;quot;2.0.5&amp;quot;)
            }
        }
    }
}

dependencies {
    testImplementation platform(&amp;quot;org.testcontainers:testcontainers-bom:2.0.5&amp;quot;)
    testImplementation &amp;quot;org.testcontainers:testcontainers-jdbc&amp;quot;
    testImplementation &amp;quot;org.testcontainers:testcontainers-junit-jupiter&amp;quot;
    testImplementation &amp;quot;org.testcontainers:testcontainers-postgresql&amp;quot;
    testImplementation &amp;quot;org.testcontainers:testcontainers&amp;quot;
    // ... autres dépendances Spring Boot
}&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;Le `resolutionStrategy.eachDependency`はBOMをバイパスする唯一の方法だ`spring-boot-dependencies`管理されている Spring Boot プラグインによって。等しさのテストは`details.requested.name == &amp;quot;testcontainers&amp;quot;`は意図的に制限的です：コアモジュールのみを強制します。モジュール`testcontainers-*`Testcontainers 2.0.5のBOM（明示的に宣言したもの）に従います。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_最終結果&amp;quot;&amp;gt;最終結果&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;$ ./gradlew build --no-daemon

&amp;amp;gt; Task :consoleLauncherTest
[2 containers found]
[2 containers started]
[2 containers successful]

BUILD SUCCESSFUL in 1m 16s&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;Testcontainers 2.0.5 + docker-java 3.7.1 は、Docker Engine 29.4.1 を介して PostgreSQL コンテナを finally 作成できるようになりました。最終的なビジネスエラー（Cucumber テストでの HTTP 500）は、ビルドスクリプトとは完全に独立したアプリケーションの問題です。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_修正のサマリーテーブル&amp;quot;&amp;gt;修正のサマリーテーブル&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;table class=&amp;quot;tableblock frame-all grid-all stretch&amp;quot;&amp;gt;
&amp;lt;colgroup&amp;gt;
&amp;lt;col style=&amp;quot;width: 25%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 25%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 25%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 25%;&amp;quot;&amp;gt;
&amp;lt;/colgroup&amp;gt;
&amp;lt;thead&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;th class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;#&amp;lt;/th&amp;gt;
&amp;lt;th class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;ファイル&amp;lt;/th&amp;gt;
&amp;lt;th class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;問題&amp;lt;/th&amp;gt;
&amp;lt;th class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;修正&amp;lt;/th&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/thead&amp;gt;
&amp;lt;tbody&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;1&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;code&amp;gt;buildSrc/src/main/groovy/jhipster.cucumber-conventions.gradle&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;変数`reportsDir`存在しない&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;code&amp;gt;outputs.dir(cucumberReportsDir)&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;2&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;code&amp;gt;buildSrc/src/main/groovy/jhipster.cucumber-conventions.gradle&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;`main`非推奨の Gradle 9&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;code&amp;gt;mainClass&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;3&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;code&amp;gt;build.gradle&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;`sourceCompatibility`トップレベルでは Gradle 9 は禁止されています&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;ブロック`java { sourceCompatibility = JavaVersion.VERSION_21 }`&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;4&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;code&amp;gt;build.gradle&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;Groovyのアサーションの構文が無効です&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;code&amp;gt;assert &amp;amp;#8230;&amp;amp;#8203; in [&amp;quot;17&amp;quot;, &amp;quot;21&amp;quot;, &amp;quot;23&amp;quot;, &amp;quot;24&amp;quot;]&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;5&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;code&amp;gt;build.gradle&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;暗黙的依存`compileKotlin`→&amp;lt;code&amp;gt;openApiGenerate&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;code&amp;gt;afterEvaluate { tasks.named(&amp;quot;compileKotlin&amp;quot;).dependsOn(&amp;quot;openApiGenerate&amp;quot;) }&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;6&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;code&amp;gt;gradle.properties&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;`gitPropertiesPluginVersion`互換性のない Java 21&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;code&amp;gt;2.5.7&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;7&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;Gradle キャッシュ&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;docker-java 3.5.1 テスト済み、解決されたが不十分です&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;パージュ + 通過 docker-java 3.7.1&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;8&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;code&amp;gt;build.gradle&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;Testcontainers 1.20.6 は Docker Engine 29 と互換性がありません&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;Testcontainers 2.0.5 + プレフィックスの強制`testcontainers-*`+ resolutionStrategy と Spring Boot BOM の比較&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/tbody&amp;gt;
&amp;lt;/table&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_結論&amp;quot;&amp;gt;結論&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;JHipster/GradleのビルドがGradle 9 + Docker Engine 29へのアップグレード後にクラッシュする場合、エラーは2つのカテゴリに分類されます：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;ビルドスクリプトのエラー&amp;lt;/strong&amp;gt;(最初の6つ) : Gradle 9は、何年も機能していたプロパティと構文を削除します (&amp;lt;code&amp;gt;sourceCompatibility=&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;main =&amp;lt;/code&amp;gt;, `reportsDir`これらは新しいAPIを知った後の機械的な移行です。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;Dockerランタイムエラー&amp;lt;/strong&amp;gt;(最後の2つ) : Docker Engine 29.4.1 は API バージョン &amp;amp;lt; 1.40 のクライアントを除外します。 Testcontainers 1.20.6 (Spring Boot 3.4.5 によって強制されます) は、API バージョン 1.32 を送信する docker‑java 3.4.1 を使用します。 問題を解決するのは、アーティファクトの名前変更とバージョンの強制を経由で行われる Testcontainers 2.0.5 + docker‑java 3.7.1 のみです。`resolutionStrategy.eachDependency`Spring Bootの暗黙のBOMを回避する唯一の手段として。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;プロジェクトのルートにある Gradle ビルドスクリプトは現在きれいです。`./gradlew build`Java 21、Gradle 9.4.1、Spring Boot 3.4.5、Docker Engine 29.4.1 に移行しました。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;</description>
        </item><item>
            <title>AsciiDocを使ったAIエージェントの統治：コンテキスト漏れのないOpencodeセッションのための私のEager/Lazy戦略</title>
            <link >https://cheroliv.com/blog/2026/0108_gouvernance_agent_opencode_eager_lazy_post.html</link>
            <pubDate>Fri, 24 Apr 2026 00:00:00 +0000</pubDate>
            <guid isPermaLink="false">blog/2026/0108_gouvernance_agent_opencode_eager_lazy_post.html</guid>
            <description>&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_要約&amp;quot;&amp;gt;要約&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;Opencode のような AI エージェントと複数のセッションにわたる複雑なプロジェクトで作業するとき、根本的な問題に直面します：&amp;lt;strong&amp;gt;コンテキストの漏洩&amp;lt;/strong&amp;gt;. エージェントは前のセッションを覚えていない。彼/彼女に説明されたすべて&amp;amp;#8201;&amp;amp;#8212;&amp;amp;#8201;アーキテクチャ、慣習、バックログの状態&amp;amp;#8201;&amp;amp;#8212;&amp;amp;#8201;が失われている。このコンテキストを毎回再構築するのはコストがかかり、遅く、エラーの原因となる。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;この記事では、私がこの問題を解決するために構築した職人的戦略を紹介します：AsciiDocファイルに基づく持続的なガバナンスシステム、二分法を含む&amp;lt;strong&amp;gt;熱心な/怠惰な&amp;lt;/strong&amp;gt;コンテキストトークンの消費を最適化するために、そして一つ&amp;lt;strong&amp;gt;必須のセッション終了手続き&amp;lt;/strong&amp;gt;継続性を確保するために。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_シーン月曜日_4月21日_9時00分&amp;quot;&amp;gt;シーン：月曜日 4月21日 9時00分&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;Opencodeを再開して、Gradleプラグインの作業を再開します`plantuml-plugin`. 昨晩、私は三時間を費やして、APIキーのプールアーキテクチャのエージェントと議論しました&amp;amp;#8201;&amp;amp;#8212;&amp;amp;#8201;ラウンドロビンローテーション、クォータ管理、自動フォールバック。今朝、そのエージェントは私を見て、金魚の目のように見つめました。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;em&amp;gt;&amp;lt;em&amp;gt;_&amp;amp;#8201;&amp;amp;#8212;&amp;amp;#8201;こんにちは、私はOpencodeのアシスタントです。今日はどのようにお手伝いできますか？ &amp;lt;/em&amp;gt;_&amp;lt;/em&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;ない&amp;amp;#8201;&amp;amp;#8212;&amp;amp;#8201;あー、はい、 APIキーのプール, 私たちはYAMLの構造のところまで来ていた。 ない&amp;amp;#8201;&amp;amp;#8212;&amp;amp;#8201;注意,&amp;lt;code&amp;gt;PlantumlManager`これは Kotlin のシングルトンオブジェクトであって、クラスではありません。いいえ&amp;amp;#8201;&amp;amp;#8212;&amp;amp;#8201;いいえ、昨日決めたのは`SyntaxValidationResult`残っていた密封クラスのネストされた内部`PlantumlService&amp;lt;/code&amp;gt;.&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;全部やり直さなければならない。むしろ、すべてを再説明する必要がある。私はセッションの最初の20分を、昨日エージェントがすでに手にしていたコンテキストを再構築することに費やす。トークンを無駄にした20分。コードを書けるはずの20分なのに、必須の教育的説明に時間を費やしている。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;Opencodeのバグではありません。これは会話型LLMの本質です：セッション間では、作業メモリは&amp;lt;strong&amp;gt;完全に削除された&amp;lt;/strong&amp;gt;. エージェントは前の任務を覚えておらず、下された決定、特定された罠、私たちが一緒に書いたコードも覚えていません。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;私はそれを何十回も経験しました。同時に4つのプロジェクトで、週をまたいで続くセッションが続いています。平均して,&amp;lt;strong&amp;gt;セッション時間の30％～40％&amp;lt;/strong&amp;gt;はエージェントを再文脈化することに専念していた。 プロジェクトのセッション87において`plantuml-plugin`, 我慢できなくなった。これ以上、十回目になる説明をする余裕がなかった`AttemptEntry`トップレベルのデータクラスである`DiagramProcessor.kt`。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;システムが必要だった。ハックではない。真のガバナンス。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_創世記カオスからメソッドへ&amp;quot;&amp;gt;創世記：カオスからメソッドへ&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_最初のセッション暗黒時代&amp;quot;&amp;gt;最初のセッション：暗黒時代&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;Opencode との私の最初のプロジェクト,&amp;lt;code&amp;gt;plantuml-plugin&amp;lt;/code&amp;gt;, 何のガバナンスもなく開始した。質問を投げかけ、エージェントが答え、繰り返し、セッションが終了し、翌日はゼロからやり直す。それはセッション1で、続いてセッション2、セッション3&amp;amp;#8230;&amp;amp;#8203;そしてセッション62まで続き、そこで私は同じアーキテクチャを何度も説明し続けて累計何時間も失ったことに気付いた。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;第62回のセッションでは、数字はここにあります：&amp;lt;strong&amp;gt;198の単体テストがパスします&amp;lt;/strong&amp;gt;, &amp;lt;strong&amp;gt;42つの機能テストが検証済み&amp;lt;/strong&amp;gt;, プラグインは動作します。 しかし、認知的コストは耐え難いです。 新しいセッションごとに、プロジェクトの構造についての20分間の独白から始まります。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_site_yml_の_エピソードが破壊されました_セッション_2_bakery_plugin&amp;quot;&amp;gt;site.yml の エピソードが破壊されました (セッション 2, bakery-plugin)&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;この方法も災害から生まれます。 プロジェクトについて`bakery-gradle`, セッション 2 で、エージェントにファイルを変更するように依頼します。&amp;lt;code&amp;gt;site.yml&amp;lt;/code&amp;gt;. エージェントは、ファイルがバージョン管理されているか確認せずに、する`Write`内容を上書きする。結果: 実際のトークン（Firebase APIキー、デプロイシークレット）は偽のプレースホルダーに置き換えられます。ファイルはgitに入っていなかった&amp;amp;#8201;&amp;amp;#8212;&amp;amp;#8201;それは&amp;amp;#8230;&amp;amp;#8203;にあった`.gitignore`秘密を守るために。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;バックアップなし。なし`git restore`可能です。 私は詰まっています。 設定ファイルを手動で再構築し、パスワードマネージャーからトークンを見つけ出し、すべてを元に戻す必要があります。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;それはこのフラストレーションから生まれる&amp;lt;strong&amp;gt;絶対ルール 1b&amp;lt;/strong&amp;gt; :&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;em&amp;gt;&amp;lt;em&amp;gt;_ &amp;lt;strong&amp;gt;決して潰さない&amp;lt;/strong&amp;gt;設定ファイルと`Write`完了するとき`Edit`部分的に十分です。&amp;lt;strong&amp;gt;決して置き換えてはいけません&amp;lt;/strong&amp;gt;� 機密の値をダミーの値で。&amp;lt;strong&amp;gt;確認する &amp;lt;code&amp;gt;git check-ignore&amp;lt;/code&amp;gt; と `git ls-files&amp;lt;/strong&amp;gt;変更の前に &amp;lt;/em&amp;gt;_&amp;lt;/em&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;この規則は、今では私のすべてのファイルに石に刻まれているように固定されています`AGENT.adoc` et `INDEX.adoc`4つのプロジェクトにおいて、実際のミスから生まれ、私に1時間の手作業のコストをかけた。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_markdown_asciidoc_の移行セッション_1cheroliv_com&amp;quot;&amp;gt;Markdown → AsciiDoc の移行（セッション 1、cheroliv.com）&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;2026年4月25日、&amp;lt;code&amp;gt;cheroliv.com&amp;lt;/code&amp;gt;, 私は抜本的な決定を下す：Markdown のガバナンス全体を AsciiDoc に変換する。これは美的ではない。機能的だ。AsciiDoc は LLM がよりよく読める意味構造を提供する：階層的セクション、型付きテーブル、アドモニション (&amp;lt;code&amp;gt;NOTE&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;WARNING&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;CAUTION&amp;lt;/code&amp;gt;), マシン可読のドキュメント属性&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;セッション 1 の`cheroliv.com`構造を形式化する：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;変換の`AGENTS.md` en &amp;lt;code&amp;gt;AGENT.adoc&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;専門エージェントの作成:`CODER.adoc`, &amp;lt;code&amp;gt;SCRUM_MASTER.adoc&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;PLANTUML_DESIGNER.adoc&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;Eager/Lazy構造の作成：&amp;lt;code&amp;gt;INDEX.adoc&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;SESSIONS_HISTORY.adoc&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;AGENT_SESSION_MANAGER.adoc&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;SESSION_CHECKLIST.adoc&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;PROCEDURES.adoc&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;1つのコミット：&amp;lt;code&amp;gt;90975e9 refactor: migrate agent governance from Markdown to AsciiDoc&amp;lt;/code&amp;gt;. そしてサイトは引き続き機能しています。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div id=&amp;quot;diag-timeline&amp;quot; class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
skinparam backgroundColor #FEFEFE
skinparam handwritten false

title セッションの進化 — セッション1から150+まで
legend top
    |= Couleur |= Projet |
    | &amp;amp;lt;#4CAF50&amp;amp;gt; | cheroliv.com |
    | &amp;amp;lt;#2196F3&amp;amp;gt; | plantuml-plugin |
    | &amp;amp;lt;#FF9800&amp;amp;gt; | bakery-plugin |
    | &amp;amp;lt;#9C27B0&amp;amp;gt; | magic-stick |
endlegend

concise &amp;quot;アクティブなセッション&amp;quot; as S

@S
0 is &amp;quot;.md 生&amp;quot;
1 is &amp;quot;移行\nAsciiDoc&amp;quot;
10 is &amp;quot;Eager/Lazy\n形式化された&amp;quot;
62 is &amp;quot;安全ルール
(site.yml)&amp;quot;
87 is &amp;quot;クラック
コンテキスト&amp;quot;
109 is &amp;quot;最適化
-60% トークン&amp;quot;
133 is &amp;quot;133回のセッション\n240テスト合格&amp;quot;

S@0 -&amp;amp;gt; S@1 : Session 1\n(cheroliv.com)
S@1 -&amp;amp;gt; S@10
S@10 -&amp;amp;gt; S@62 : Session 62\n(plantuml-plugin)
S@62 -&amp;amp;gt; S@87 : Session 87\n(Cry 4 help)
S@87 -&amp;amp;gt; S@109 : Session 109\n(API Key Pool)
S@109 -&amp;amp;gt; S@133 : Session 133\n(Aujourd&amp;#39;hui)

@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;上記のタイムラインは実際の進行を示しています。転換点はセッション87です。ここで繰り返しの再コンテキスト化のフラストレーションが許容閾値を超え、Eager/Lazyメソッドは単なるアイデアではなく義務となります。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_戦略深掘りeagerlazy&amp;quot;&amp;gt;戦略：深掘りEager/Lazy&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_哲学_認知への応用コンピューティングキャッシュ&amp;quot;&amp;gt;哲学 : 認知への応用コンピューティングキャッシュ&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;私のアプローチは、コンピュータのキャッシュ管理から直接インスピレーションを得ています。すべてが&amp;lt;strong&amp;gt;批判的で頻繁に使用される&amp;lt;/strong&amp;gt;すぐにアクセス可能でなければならない&amp;lt;strong&amp;gt;熱心な&amp;lt;/strong&amp;gt;あるものはすべて&amp;lt;strong&amp;gt;コンテキスト依存のまたは大容量の&amp;lt;/strong&amp;gt;� 必要に応じてロードされなければならない (&amp;lt;strong&amp;gt;怠惰な&amp;lt;/strong&amp;gt;).&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;table class=&amp;quot;tableblock frame-all grid-all stretch&amp;quot;&amp;gt;
&amp;lt;colgroup&amp;gt;
&amp;lt;col style=&amp;quot;width: 6.6666%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 6.6666%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 6.6666%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 6.6666%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 6.6666%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 6.6666%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 6.6666%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 6.6666%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 6.6666%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 6.6666%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 6.6666%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 6.6666%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 6.6666%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 6.6666%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 6.6676%;&amp;quot;&amp;gt;
&amp;lt;/colgroup&amp;gt;
&amp;lt;tbody&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;Eager (ダッシュボード)&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;Lazy (オーナーマニュアル)&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;サイズ&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;amp;lt; 100 行, &amp;amp;lt; 10k トークン&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;無制限、詳細&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;読み込み&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;自動、セッション開始時&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;エージェントの要請により&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;内容&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;絶対的なルール、通常の任務、危機的な状態&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;セッションアーカイブ、完全な履歴、詳細な手順、技術資料&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;役割&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;エージェントをすぐに方向づける&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;深いコンテキストの質問に答える&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/tbody&amp;gt;
&amp;lt;/table&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_eager_ファイル_ダッシュボード&amp;quot;&amp;gt;Eager ファイル : ダッシュボード&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;これらのファイルは各プロジェクトのルートに存在し、エージェントによって各セッションの開始時に自動的に読み込まれます。それらは&amp;lt;strong&amp;gt;ダッシュボード&amp;lt;/strong&amp;gt;-- 重要な情報、すぐにアクセス可能。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div id=&amp;quot;diag-eager-lazy&amp;quot; class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
skinparam defaultTextAlignment center
skinparam wrapWidth 200

package &amp;quot;プロジェクトのルート (Eager - 自動読み込み)&amp;quot; {
    component &amp;quot;&amp;amp;lt;b&amp;amp;gt;AGENT.adoc&amp;amp;lt;/b&amp;amp;gt;
絶対のルール
構造 &amp;amp;amp; 慣習&amp;quot; as AGENT
    component &amp;quot;&amp;amp;lt;b&amp;amp;gt;PROMPT_REPRISE.adoc&amp;amp;lt;/b&amp;amp;gt;
セッション Nのミッション
概要 N-1&amp;quot; as PROMPT
    component &amp;quot;&amp;amp;lt;b&amp;amp;gt;INDEX.adoc&amp;amp;lt;/b&amp;amp;gt;
エントリーポイント
ルール + セッション&amp;quot; as INDEX
    component &amp;quot;&amp;amp;lt;b&amp;amp;gt;*_ESSENTIALS.adoc&amp;amp;lt;/b&amp;amp;gt;\n業務コンテキスト\n重要&amp;quot; as ESS
}

package &amp;quot;.agents/ (Lazy - オンデマンドで読み込み)&amp;quot; {
    component &amp;quot;&amp;amp;lt;b&amp;amp;gt;sessions/N-*.adoc&amp;amp;lt;/b&amp;amp;gt;\n詳細なアーカイブ\n決定 &amp;amp;amp; 出力&amp;quot; as SESS
    component &amp;quot;&amp;amp;lt;b&amp;amp;gt;SESSIONS_HISTORY.adoc&amp;amp;lt;/b&amp;amp;gt;
サマリーテーブル
日付/タイプ/スコア&amp;quot; as HIST
    component &amp;quot;&amp;amp;lt;b&amp;amp;gt;PROCEDURES.adoc&amp;amp;lt;/b&amp;amp;gt;
セッション終了テンプレート
6ステップ&amp;quot; as PROC
    component &amp;quot;&amp;amp;lt;b&amp;amp;gt;*_REFERENCE.adoc&amp;amp;lt;/b&amp;amp;gt;
完全なアーキテクチャ
技術参照&amp;quot; as REF
    component &amp;quot;&amp;amp;lt;b&amp;amp;gt;COMPLETED_TASKS_ARCHIVE&amp;amp;lt;/b&amp;amp;gt;
完了したタスク
月ごと&amp;quot; as ARCH
    component &amp;quot;&amp;amp;lt;b&amp;amp;gt;AGENT_MODUS_OPERANDI.adoc&amp;amp;lt;/b&amp;amp;gt;
戦略ドキュメント
方法論&amp;quot; as MOD
    component &amp;quot;&amp;amp;lt;b&amp;amp;gt;*_REFERENCE.adoc&amp;amp;lt;/b&amp;amp;gt;
Boot tests, A/B partition
特定のコンテキスト&amp;quot; as SPEC
}

AGENT --&amp;amp;gt; PROMPT : &amp;quot;参考文献&amp;quot;
AGENT --&amp;amp;gt; INDEX : &amp;quot;参考文献&amp;quot;
INDEX --&amp;amp;gt; SESS : &amp;quot;インデックスする&amp;quot;
INDEX --&amp;amp;gt; HIST : &amp;quot;インデックスする&amp;quot;
INDEX --&amp;amp;gt; PROC : &amp;quot;参照&amp;quot;
INDEX --&amp;amp;gt; ARCH : &amp;quot;参照&amp;quot;
INDEX --&amp;amp;gt; REF : &amp;quot;参照&amp;quot;
PROMPT --&amp;amp;gt; SESS : &amp;quot;アーカイブ N-1&amp;quot;
PROMPT --&amp;amp;gt; ESS : &amp;quot;ビジネスコンテキスト N&amp;quot;

@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;AGENT.adoc&amp;lt;/strong&amp;gt;-- マスターファイル。について`cheroliv.com`, 200行あり、以下を含みます :&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;プロジェクトの絶対的なルール（コミットは許可がなければ、`rm`確認なし)&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;プロジェクトの構造とコーディング規約&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;基本的なコマンド (&amp;lt;code&amp;gt;./gradlew serve&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;./gradlew test&amp;lt;/code&amp;gt;)&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;エピックとプロダクトバックログ(優先順位付けられたユーザーストーリー)&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;横断的な品質基準（アクセシビリティ、レスポンシブ、互換性）&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;上`bakery-plugin`, ルール0は異なります :&amp;lt;strong&amp;gt;./gradlew -q publishToMavenLocal` ソースコードを変更するたびに必須です&amp;lt;/strong&amp;gt;. ローカル JAR を再公開せずにプラグインをテストしたため、まだパッケージ化されていないコードをデバッグするのに1時間も無駄にしてしまった。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;PROMPT_REPRISE.adoc&amp;lt;/strong&amp;gt;-- 現在のセッションのミッション。各セッションの終了時に更新され、以下を含みます：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;セッション番号と優先ミッション&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;前回のセッションのまとめ（行われたこと、まだやるべきこと）&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;現在のセッションの受入基準&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;特定の技術的なリマインダー&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;.agents/INDEX.adoc&amp;lt;/strong&amp;gt;-- エントリーポイント。これは絶対的なルール、最近のセッション、そして特に&amp;lt;strong&amp;gt;プロジェクトポートフォリオ&amp;lt;/strong&amp;gt;同じ方法論で管理されています。今日現在、ここに5つのプロジェクトが掲載されています :&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-none hljs&amp;quot;&amp;gt;----
----
| magic-stick    | Session 23 | SCRIPT_VERIFICATION.adoc | 2026-04-27 |
| bakery-gradle  | Session 11 | TEST_COVERAGE_ANALYSIS   | 2026-04-27 |
| cheroliv.com   | Session 9  | TEST_COVERAGE_ANALYSIS   | 2026-04-27 |
| plantuml-gradle| Session 133| TEST_COVERAGE_ANALYSIS   | 2026-04-23 |
| jhipster-gradle-plugins | Session 1 | TEST_COVERAGE_ANALYSIS | 2026-04-28 |
----

(No content)`*_ESSENTIALS.adoc`-- Session 109（plantuml-plugin）による最近の追加で、Eagerコンテキストをさらに最適化。API キー プール上のビジネス コンテキスト 200 行をロードする代わりに、必須の 50 行だけをロードし、残りの 150 行は LAZY の状態のままにしておきます`*_REFERENCE.adoc`.

�測定結果 : ～への移行**~25k トークン EAGER から ~10k トークン**(60%の利益)。エージェントはもはやエネルギーを消費するリマインダーを必要としない。

==== 欠落しているリンク : `opencode.json

実は告白しておかなければならないことがあります。ドキュメントに残すのをうっかり忘れそうになったことです。これらの .adoc ファイルの上には、動作に不可欠な極めて小さな JSON ファイルがあります。それは`opencode.json`そして六行です。文字通り六行です。

[source,json]
----
{
  &amp;quot;$schema&amp;quot;: &amp;quot;https://opencode.ai/config.json&amp;quot;,
  &amp;quot;instructions&amp;quot;: [
    &amp;quot;AGENT.adoc&amp;quot;
  ]
}
----

このファイルがOpencodeに伝える：「起動時に、ロード」`AGENT.adoc`「自動的に。」 彼がいないと、エージェントは私が記事の冒頭で説明した通り、真っ白なページです。彼がいると、エージェントはすでに絶対的なルール、プロジェクトのアーキテクチャ、そして必須のコマンドを手にしています — 私が「こんにちは」と言う前でも。

私は偶然、このファイルの重要性に気づきました。 上で`bakery-plugin`, それは存在していなかった。私はなぜそのエージェントが他のプロジェクトよりもこのプロジェクトで系統的にもっと「迷子」だったのか疑問に思っていた。絶対的なルールは確かにその中にあった`AGENT.adoc`— しかし`AGENT.adoc`一度も充電されていなかった。 エージェントは私が読むように言ったものだけを、各セッションごとに手動で読んでいた。 これはセッション11の`bakery-plugin`私がその欠如に気づいたとき`opencode.json`. 私はそれを作成しました — そしてセッション12は他のセッションと同様に開始されました。

このファイルは今では私にとってとても明白で、もうそれについて考えることすらしなくなった。ツールに詳しすぎる開発者が陥りがちな典型的なミスだ。今日では、私はこれを常に*avant*作成するようにしている。`AGENT.adoc`. これが最初の石です。

==== INDEX.adoc`の二重性

もう一つ、明確にすべき微妙な点があります：`INDEX.adoc`に住んでいる`.agents/`— LAZYとして提示したフォルダ。しかし、私はこれをすべてのテーブルでEAGERとしてリストしている。ここには明らかな緊張がある。

実際の現場 : ファイル`.agents/INDEX.adoc`自動的に正しく読み込まれ、同様に`AGENT.adoc` et `PROMPT_REPRISE.adoc`. 彼らは中に`.agents/`組織上の理由により — 根を侵さないように — しかし、彼らの動作はEAGERである。

上に`plantuml-plugin`, `INDEX.adoc`これは200行で、過去のセッションの教訓である歴史とともに、絶対に*完全な*ルール、スコア付きのEPIC、そしてプロジェクトのポートフォリオを含んでいます。これはエージェントが「現在の状況」を確認するために参照するドキュメントです。Sur`bakery-plugin`, 最近のロードマップとセッションで150行です。

意図的な冗長性の間`AGENT.adoc` et `INDEX.adoc`� 驚くかもしれません。 絶対的なルールは両方に存在します。 なぜ？ なぜなら、それらは二つの異なる役割を果たしているから：の中で`AGENT.adoc`, それらは*説明的*です (ルールのストーリーテリング、学んだ教訓) ; 中で`INDEX.adoc`, それらは *実行可能* (裸のルール、正当化なし、迅速な参照のため)。 エージェントは読む`AGENT.adoc`一度理解するために；彼は読み返す`INDEX.adoc`各セッションで*適用*する。2つの用途、2つのフォーマット。

[plantuml, format=svg, id=diag-dualite-agent-index, alt=&amp;quot;Comparaison entre AGENT.adoc (narratif) et INDEX.adoc (exécutif)&amp;quot;]
----
@startuml
skinparam backgroundColor #FEFEFE
skinparam defaultTextAlignment center

title 二重性 AGENT.adoc ←→ INDEX.adoc
left to right direction

rectangle &amp;quot;AGENT.adoc
(根 — EAGER)&amp;quot; as AGENT #E3F2FD {
  rectangle &amp;quot;**ナラティブフォーマット**
ルールのストーリーテリング
学んだ教訓、コンテキスト&amp;quot; as NARR
  rectangle &amp;quot;🏗️**完全なアーキテクチャ**
プロジェクト構造、コンポーネント
詳細なユーザーストーリーバックログ&amp;quot; as ARCHI
  rectangle &amp;quot;📋 **解説ルール**
なぜルールは存在するのか
インシデントの履歴&amp;quot; as EXPL
}

rectangle &amp;quot;INDEX.adoc\n(.agents/ — EAGER)&amp;quot; as INDEX #E8F5E9 {
  rectangle &amp;quot;⚡ **エグゼクティブフォーマット**
裸のルール、正当化なし
迅速な相談&amp;quot; as EXEC
  rectangle &amp;quot;📊 **Roadmap &amp;amp;amp; EPICs**
サマリーテーブル
進行状況, スコア, 優先度&amp;quot; as ROAD
  rectangle &amp;quot;🌐 **プロジェクトポートフォリオ**
横断ビュー
5つの同期プロジェクト&amp;quot; as PORT
}

AGENT --&amp;amp;gt; INDEX : &amp;quot;Agent が AGENT.adoc を
1 回 読んで **理解する**&amp;quot;
INDEX --&amp;amp;gt; AGENT : &amp;quot;AgentはINDEX.adocを読み直しました
各セッションで**適用**する&amp;quot;

note bottom of AGENT
  Taille max : 200 lignes
end note

note bottom of INDEX
  Taille max : 200 lignes
  Source de vérité en cas de divergence
end note

@enduml
----

この意図的な冗長性は設計上の選択です。これらはEAGERトークンの追加で約50行消費しますが、エージェントが常にルールを目の前に持てるように保証します。つまり、即時の従順を助ける簡潔なフォーマットでも同様です。

=== LAZY ファイル: 所有者のためのマニュアル

これらのファイルは[場所]に存在します`.agents/`それらは、エージェントが必要とする時だけ読まれる。それらは、方法の真の財産を構成する。なぜなら、それらは現在のコンテキストを汚すことなくプロジェクトの知識を蓄積するからである。

[plantuml, format=svg, id=diag-agents-tree, alt=&amp;quot;Arborescence complète du dossier .agents/&amp;quot;]
----
@startuml
skinparam folderBackgroundColor #E3F2FD
skinparam folderBorderColor #1565C0
skinparam fileBackgroundColor #FFF3E0
skinparam fileBorderColor #EF6C00

folder &amp;quot;.agents/&amp;quot; as ROOT {
  file &amp;quot;INDEX.adoc
(EAGER -- 200 行)&amp;quot; as IDX #E8F5E9
  file &amp;quot;AGENT_SESSION_MANAGER.adoc\n(テンプレート セッション)&amp;quot; as ASM
  file &amp;quot;SESSION_CHECKLIST.adoc
(いつ変更するか)&amp;quot; as CHK
  file &amp;quot;PROCEDURES.adoc\n(6段階 + LAZY/EAGER)&amp;quot; as PRO
  file &amp;quot;SESSIONS_HISTORY.adoc\n(すべてのセッション)&amp;quot; as HIS

  folder &amp;quot;セッション/&amp;quot; as SESS {
    file &amp;quot;1-chore-migration.adoc&amp;quot; as S1
    file &amp;quot;109-形式化-lazy.adoc&amp;quot; as S109 #FFECB3
    file &amp;quot;133-epic11-article.adoc&amp;quot; as S133
    file &amp;quot;... +130 他の&amp;quot; as SMORE
  }

  folder &amp;quot;アーカイブ/&amp;quot; as ARCH {
    file &amp;quot;COMPLETED_TASKS_2026-04.adoc&amp;quot; as CTA
    file &amp;quot;SESSIONS_HISTORY_83-95.adoc&amp;quot; as SHIST
    folder &amp;quot;セッションのサマリー/&amp;quot; as SUM {
      file &amp;quot;SESSION_64_SUMMARY.adoc&amp;quot; as SU64
      file &amp;quot;SESSION_73_SUMMARY.adoc&amp;quot; as SU73
      file &amp;quot;...&amp;quot; as SUMORE
    }
    folder &amp;quot;プロンプトアーカイブ/&amp;quot; as PARCH {
      file &amp;quot;PROMPT_REPRISE_S65.adoc&amp;quot; as PR65
      file &amp;quot;PROMPT_REPRISE_S75.adoc&amp;quot; as PR75
      file &amp;quot;...&amp;quot; as PMORE
    }
  }
}

IDX --&amp;amp;gt; SESS : &amp;quot;索引&amp;quot;
IDX --&amp;amp;gt; HIS : &amp;quot;索引&amp;quot;
IDX --&amp;amp;gt; ARCH : &amp;quot;参照&amp;quot;

note right of S109
  Session 109 =
  Formalisation stratégie
  LAZY/EAGER
  Token : ~25k → ~10k
end note

@enduml
----

上記のツリー構造はフォルダーの実際の構造を示しています。`.agents/`上に`plantuml-plugin`, 最も成熟したプロジェクト。 注目してください 3層の深さ : ルートファイル（メタデータ）, ディレクトリ`sessions/`（年代順アーカイブ）, と ファイル`archives/`(集約と要約)。この深さが、単なるTODOファイルのガバナンスを変える**完全な組織記憶**。

**.agents/sessions/{N}-{titre}.adoc**-- 各セッションの詳細なアーカイブ。現在：

* `plantuml-plugin`:**133件のアーカイブ済みセッション**(セッション1から133まで)
* `bakery-plugin` : **11 セッション**
* `magic-stick` : **23セッション**
* `cheroliv.com` : **9 正式なセッション**+ 7セッション（プリシステム）が遡及的に再構築されました

各アーカイブはセッションの完全なコンテキスト、行われた決定、遭遇した問題とその解決、実行されたコマンドとその出力を含みます。

**.agents/SESSIONS_HISTORY.adoc**-- すべてのセッションのスコア付きサマリーテーブル。例:`cheroliv.com`:

----

| -6 | 2025-05 | chore | Initialisation projet Gradle/JBake | 7/10 |  1 | 2026-04-25 | chore | Migration gouvernance agent | 8/10 |  7 | 2026-04-27 | debug/fix | Correction publishSite | 9/10 |  8 | 2026-04-27 | analyse | Analyse article 0108 | 7/10

**.agents/COMPLETED_TASKS_ARCHIVE_{mois}.adoc**-- 完了したタスクを月ごとにアーカイブし、アクティブなバックログを過負荷にしないようにします。ユーザーストーリーが完了すると、ここに移行します。バックログは読みやすく保たれます：アクティブなアイテムは最大10個。

**.agents/PROCEDURES.adoc**-- 終了セッション手順の詳細なテンプレート。長いが、エージェントが方法を学ぶときに一度だけ読まれる。その後、手順は機械的になる。

**.agents/AGENT_MODUS_OPERANDI.adoc**完全な戦略ドキュメント。 上で`plantuml-plugin`, このファイルは**900+行**そして実際にはその名前が付いています`AGENT_METHODOLOGIES.adoc`— この記事を書いている間と実際に実装される間で、私は名前を変更しました。この種の命名のズレは、進化する職人製のシステムでは避けられない。重要なのは命名規則です：ファイルが*メソッド*を文書化している場合、それはで始まります。`AGENT_`または明示的なプレフィックス。Eager/Lazyの手法を文書化し、従うべきパターンと避けるべきアンチパターンを示しています。LAZYであるのは、エージェントが各セッションごとに戦略全体を読み直す必要がなく、あいまいさがあるときだけだからです。

(Empty)`*_REFERENCE.adoc`** -- プロジェクト固有の技術的参照。について`magic-stick`, 密集した2つのLAZYファイル:

* `AB_PARTITION_REFERENCE.adoc`(147 行) -- A/B パーティション GPT アーキテクチャ, スクリプト`update-system.sh`, 推定サイズ, ロールバックメカニズム
* `BOOT_TEST_REFERENCE.adoc`(144 行) -- QEMU + VNC を使用して物理ハードウェアなしで ISO のブートをテストする手順、BIOS/UEFI チェックリスト、CI/CD の制限事項

上`plantuml-plugin` :

* `ARCHITECTURE.adoc`(134 行) -- 11 のデータクラスの構造, 注意点（避けるべき罠）, 最適化されたテストコマンド
* `API_KEY_POOL_REFERENCE.adoc`-- キー プールの完全な詳細 (LAZY pendant que`ESSENTIALS`です EAGER)

== �専門エージェント：仮想チーム

ガバナンスは受動的なファイルに限定されません。私は形式化した**�専門エージェントの役割**専用のLAZYファイル内に、タスクの種類に応じた期待されるワークフローが定義されています。

|===
|エージェント |ファイル |役割 |プロジェクト |**コードを書く** |`CODER.adoc` |FTL/CSS/JS の実装、セマンティックタグ、アクセシビリティ基準 |cheroliv.com |**スクラムマスター** |`SCRUM_MASTER.adoc` |ユーザーストーリーの計画、サブタスクへの分割、依存関係の検出 |cheroliv.com |**PlantUML デザイナー** |`PLANTUML_DESIGNER.adoc` |�図の作成, PUML構文, JBake統合 |cheroliv.com
|===

ファイル`CODER.adoc`上`cheroliv.com`具体的なルールが含まれています：_一つだけ`&amp;amp;lt;h1&amp;amp;gt;`python print(&amp;quot;ページごとに、パスにプレフィックスをつける&amp;quot;)`${content.rootpath}`_, _Déclarer la langue `&amp;amp;lt;html lang=&amp;quot;${content.lang!&amp;quot;fr&amp;quot;}&amp;quot;&amp;amp;gt;`_. これらの規則は一度書かれると、セッション1からエージェントによって自動的に遵守されます。

ファイル`SCRUM_MASTER.adoc`納品物の構造を課す：**目的**, **タスク**(代入付き座標),**受入基準**, **リスク**. 私がアクションプランを要求すると、エージェントは私が求めずにこの構造を生成します。ガバナンス**プログラム**エージェント。

==== 専門エージェントが不可欠になる時

専門エージェントの作成は自然な曲線に従います。プロジェクトの初めには、これらは必要ありません —`AGENT.adoc`十分です。しかしプロジェクトが大きくなる（たとえば、20セッションを超える場合）と、2つのシグナルがあなたに警告を発すべきです。

1. エージェントは2つの異なる分野の規則を混在させます（例：PlantUML構文とCSSルール）
2. あなたは、エージェントにすでに5回説明した慣習について訂正することに、もっと時間を費やしています。

上に`cheroliv.com`, これはセッションで起こったことです... 1. はい、最初からです。なぜなら、このプロジェクトはFTL、CSS、JSの3つの言語を使ったウェブサイトであり、AsciiDocのコンテンツとPlantUMLのダイアグラムを含んでいるからです — これらは全く関係のない3つの分野です。CODERエージェントはフォントサイズとメディアクエリを知る必要があり、PLANTUML_DESIGNERエージェントは構文を知る必要があります`@startuml`. 分離なく、エージェント CODER が私にダイアグラムを提案し、その逆も同様だった。混乱。

上`jhipster-gradle-plugins`, 私はGradleプラグイン開発に適した2つの専門エージェントを作成しました：`PLUGIN_DEVELOPER.adoc` et `BACKLOG_MANAGER.adoc`. 最初はすべての Kotlin/Gradle の規約をエンコードします（ただし`!!`, データクラス（モデル用）,`@TaskAction`タスクのため)。2番目は知っている`persistence`それになる前に安定している必要がある`assistant`開発を開始しない — mono-repo内のクリティカルな依存関係。

犯してはいけない間違い：早すぎる段階でエージェントを作りすぎること`plantuml-plugin`セッション108を待ち、APIキーのプール用の専門エージェントを正式化しました。それ以前は、業務コンテキストは`AGENT.adoc`. 経験則：専門的なエージェントは、その業務ドメインのドキュメントが100行を超えるとき正当化される。

==== セッション命名規約

小さくて取るに足らない詳細だが、100回のセッションに到達すると重要になる。アーカイブファイルはどのように命名すればよいでしょうか？

私は苦い経験から、規約が必要だと学びました — 初めは4つのプロジェクト、4つの異なるフォーマットがあり、訳がわからなくなりました。今日、私が確立した規約は：&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;{N}-{type}-{sujet-kebab-case}.adoc&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;具体例:

* `1-chore-migration-gouvernance-agent.adoc`— セッション 1、タイプの雑用
* `10-solidification-tests.adoc`— セッション10、明示的な型なし (主題だけで十分)
* `036-debug-graphify-symlink-epic9.adoc`— 3桁の番号付きソート用セッション36

セッション番号が主要なソート基準です。3桁の番号（001、036、133）を使用するプロジェクトは、99を超えたときの辞書順ソートの問題を回避します。これが今私が使っているものです`magic-stick`:

(Note: a leading space, colon, trailing space)`001-init-projet.adoc`, `036-debug-graphify-symlink-epic9.adoc`。

タイプはオプションであり、セッションのキーワード (debug, feature, refactor, docs, chore, test) から派生します。kebab-case のサブジェクトは最も重要な部分です：ファイルを開かずにセッションを見つけられるようにする必要があります。「テストの統合のタイムアウトを修正したセッションはどれだったかな？」と疑問に思う場合、答えは`124-fix-timeout-integration-test.adoc`.

再構築された歴史的セッション（ガバナンス以前に生まれたプロジェクト）については、負の数を使用しています。の`cheroliv.com`, セッション -6 から 0 までがプロジェクトのガバナンス以前の歴史全体をカバーしています。そして、ドキュメント化されていないセッションや失われたセッションについては、その中にエントリを作成します`SESSIONS_HISTORY.adoc`対応するアーカイブなし、スコアあり`?`. それは仮を装うよりも正直だ。

[plantuml, format=svg, id=diag-naming-convention, alt=&amp;quot;Arbre de décision pour le nommage des fichiers de session&amp;quot;]&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;@startuml
skinparam backgroundColor #FEFEFE
skinparam defaultTextAlignment center
skinparam wrapWidth 200&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;title セッション命名規約
start&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;:Une session se termine;
note right: Trigger &amp;quot;セッションの終わり&amp;quot;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;if (Session antérieure\nà la gouvernance ?) then (oui)
  :Numéro &amp;lt;strong&amp;gt;NÉGATIF&amp;lt;/strong&amp;gt;\n-6, -5 &amp;amp;#8230;&amp;amp;#8203; 0;
  note right: Historique\nreconstitué
  :Suffixe : reconstitution;
else (non)
  :Numéro &amp;lt;strong&amp;gt;POSITIF&amp;lt;/strong&amp;gt;\nsur 3 chiffres si &amp;amp;gt; 99;
  note right: 001, 036, 133\npour le tri lexicographique&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;literalblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;:Détecter le **TYPE**;
if (Mots-clés trouvés ?) then (oui)
  :debug / feature / refactor\ndocs / chore / test;
else (non)
  :Omettre le type\n(le sujet suffit);
endif&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;literalblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;  :Formuler le **SUJET** en kebab-case;
  note right
    Ex: fix-timeout-integration-test
    Doit permettre de retrouver
    sans ouvrir le fichier
  end note
endif&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;note right
  • 1-chore-migration-gouvernance.adoc
  • 036-debug-graphify-symlink.adoc
  • 124-fix-timeout-integration-test.adoc
  • 133-epic11-article-blog-kg.adoc
end note&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;if (Session documentée ?) then (oui)
  :Créer archive dans sessions/;
  :Ajouter ligne SESSIONS_HISTORY\navec score X/10;
else (non)
  :Ajouter ligne SESSIONS_HISTORY\navec score &amp;lt;strong&amp;gt;?&amp;lt;/strong&amp;gt;\n&amp;lt;strong&amp;gt;sans archive&amp;lt;/strong&amp;gt;;
  note right: L&amp;amp;#8217;honnêteté\nplutôt que le vide
endif&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;stop
@enduml&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;==== TEST_COVERAGE_ANALYSIS.adoc` — ステップ5 詳細分析

手順5のセッション終了の手順は最も謎めいています。それは「更新する」と言います。`TEST_COVERAGE_ANALYSIS.adoc`もしテストが追加または変更された場合。 しかし、このファイルはどのように見えるでしょうか？

上`plantuml-plugin`, それは数行から完全な構造に進化しました。ここにその安定した形があります：

[source]&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;h1 id=&amp;quot;_analyse_de_couverture_de_tests&amp;quot; class=&amp;quot;sect0&amp;quot;&amp;gt;Analyse de Couverture de Tests&amp;lt;/h1&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_suivi_des_tests&amp;quot;&amp;gt;Suivi des Tests&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;table class=&amp;quot;tableblock frame-all grid-all stretch&amp;quot;&amp;gt;
&amp;lt;colgroup&amp;gt;
&amp;lt;col style=&amp;quot;width: 20%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 20%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 20%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 20%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 20%;&amp;quot;&amp;gt;
&amp;lt;/colgroup&amp;gt;
&amp;lt;tbody&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;Classe de test&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;Type&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;Tests&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;Statut&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;Dernière MAJ&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;PlantumlServiceTest&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;unit&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;45/45&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;✅ PASS&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;2026-04-23&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;ApiKeyPoolTest&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;integration&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;15/15&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;✅ PASS&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;2026-04-20&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/tbody&amp;gt;
&amp;lt;/table&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_historique_par_session&amp;quot;&amp;gt;Historique par Session&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;| Session | Tests ajoutés | Tests modifiés | Couverture
| 133     | 0             | 2              | 100%
| 132     | 5             | 0              | 100%&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;table class=&amp;quot;tableblock frame-all grid-all stretch&amp;quot;&amp;gt;
&amp;lt;colgroup&amp;gt;
&amp;lt;col style=&amp;quot;width: 25%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 25%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 25%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 25%;&amp;quot;&amp;gt;
&amp;lt;/colgroup&amp;gt;
&amp;lt;tbody&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;----&amp;lt;/p&amp;gt;
&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;興味はファイルそのものではなく、&amp;lt;strong&amp;gt;変更点を記録する*義務である。このステップを踏まなければ、50セッション後にはどのテストが何をカバーしているのかわからなくなる。エージェントも同様だ。ファイルはプロジェクトのテストカバレッジの唯一の真実の参照となる。&amp;lt;/p&amp;gt;
&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;伝統的なテストのないプロジェクト (例えば`magic-stick`bash スクリプトをテストする), ステップ5は置き換えられます`SCRIPT_VERIFICATION.adoc`.メカニズムは同じです: スクリプトの検証状態を追跡するファイルです。ステップ5をあなたのプロジェクトに合わせて調整してくださいが、決して省略しないでください。これは、サイレントリグレッションを防ぐ安全ネットです。&amp;lt;/p&amp;gt;
&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;あなたのプロジェクトに *まったくない&amp;lt;/strong&amp;gt; テスト — ユニットテストでも、機能テストでも、スクリプトテストでも — それでも空のファイルを作成し、「やること：テスト戦略を定義する」というセクションを追加してください。これは、将来の自分にこのトピックが未処理であることを思い出させるしおりとなります。&amp;lt;/p&amp;gt;
&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;[plantuml, format=svg, id=diag-session-flow, alt=&amp;quot;Flux d&amp;amp;#8217;une session type avec Eager/Lazy et agents&amp;quot;]
----
@startuml
skinparam backgroundColor #FEFEFE&amp;lt;/p&amp;gt;
&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;start&amp;lt;/p&amp;gt;
&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;:Début session;
note right: L&amp;amp;#8217;agent est une page blanche&amp;lt;/p&amp;gt;
&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;:Chargement EAGER auto;
note right
  * AGENT.adoc (règles absolues)
  * PROMPT_REPRISE.adoc (mission N)
  * INDEX.adoc (état projet)
end note&amp;lt;/p&amp;gt;
&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;if (Mission claire ?) then (oui)
  :Exécution directe;
else (non)
  :Charge LAZY sur demande;
  note right
    * SESSIONS_HISTORY.adoc (contexte passé)
    * sessions/{N-1}-&amp;lt;strong&amp;gt;.adoc (décisions)
    * *&amp;lt;em&amp;gt;REFERENCE.adoc (architechture)
  end note
endif&amp;lt;/p&amp;gt;
&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;:Délégation agent spécialisé ?;&amp;lt;/p&amp;gt;
&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;if (CODER ?) then (oui)
  :Lit CODER.adoc;
  :Suit conventions FTL/CSS;
elseif (SCRUM Master ?) then (oui)
  :Lit SCRUM_MASTER.adoc;
  :Structure livrable imposée;
elseif (PlantUML ?) then (oui)
  :Lit PLANTUML_DESIGNER.adoc;
  :Syntaxe PUML + intégration;
else (non)
endif&amp;lt;/p&amp;gt;
&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;:Travail de la session;&amp;lt;/p&amp;gt;
&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;:Fin de session (trigger utilisateur);&amp;lt;/p&amp;gt;
&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;:Procédure 6 étapes;
note right
  1. Archive sessions/N-&amp;lt;/strong&amp;gt;.adoc
  2. Maj PROMPT_REPRISE.adoc (N+1)
  3. Maj SESSIONS_HISTORY.adoc
  4. Maj INDEX.adoc
  5. Maj TEST_COVERAGE (si applicable)
  6. Maj COMPLETED_TASKS_ARCHIVE.adoc
end note&amp;lt;/p&amp;gt;
&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;:Checklist [✅] x 6;&amp;lt;/p&amp;gt;
&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;stop
@enduml
----&amp;lt;/p&amp;gt;
&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;上記の図は、セッションの完全なライフサイクルを示しています。重要なポイントは、EAGERロード後の分岐です：ミッションが十分に明確で直接実行できる場合（80％のケース）と、エージェントがLAZYロードを行い曖昧さを解決する場合（20％のケース）があります。この判別がトークンの節約につながります。&amp;lt;/p&amp;gt;
&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;== セッション終了の手順：黄金律&amp;lt;/p&amp;gt;
&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;=== なぜ彼女は不可欠なのか&amp;lt;/p&amp;gt;
&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;この手順がないと、Eager/Lazy ストラテジーは何の役にも立ちません。それが、セッションの作業を永続的な情報に変換します。それが実行されます。&amp;lt;strong&amp;gt;ユーザーの明示的な要求により&amp;lt;/strong&amp;gt;(キーワード: &amp;quot;セッション終了&amp;quot;, &amp;quot;私が去る&amp;quot;, など), そしてそれは&amp;lt;strong&amp;gt;必須&amp;lt;/strong&amp;gt;-- 例外もなく、漏れもなく。&amp;lt;/p&amp;gt;
&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;ファイル`SESSION_CHECKLIST.adoc`理想的なセッションメトリクスを定義する：&amp;lt;/p&amp;gt;
&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;* 所要時間: 15-30分
* 変更されたファイル: 1-3個まで
* LLMの交換：5-10メッセージ
* コンテキストトークン : &amp;amp;lt; 50k&amp;lt;/p&amp;gt;
&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;セッションを変更する必要がある兆候 : _LLMが既に修正されたエラーを繰り返す&amp;lt;/em&amp;gt;、 &amp;lt;em&amp;gt;同時に3ファイル以上が変更されている&amp;lt;/em&amp;gt;、 &amp;lt;em&amp;gt;会話が50メッセージを超える&amp;lt;/em&amp;gt;。 黄金律 :&amp;lt;strong&amp;gt;2時間のセッションと混乱したデバッグより、20分のセッションを5回行う方が良い。&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;=== 6つのステップのフロー (静かに)&amp;lt;/p&amp;gt;
&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;[plantuml, format=svg, id=diag-end-session-flow, alt=&amp;quot;Flux de la procédure de fin de session&amp;quot;]
----
@startuml
skinparam defaultTextAlignment center
skinparam wrapWidth 200
skinparam activityBackgroundColor #E3F2FD&amp;lt;/p&amp;gt;
&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;start
:L&amp;amp;#8217;utilisateur dit &amp;quot;セッションの終了&amp;quot;;
note right: Mots-clés déclencheurs&amp;lt;/p&amp;gt;
&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;:Agent détecte le trigger;&amp;lt;/p&amp;gt;
&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;:Étape 1\nCréer archive\n`.agents/sessions/N-*.adoc`;
note right: Tout le contexte de la session&amp;lt;/p&amp;gt;
&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;:Étape 2\nMettre à jour\n`PROMPT_REPRISE.adoc`;
note right: Mission N + critères d&amp;amp;#8217;acceptation N+1&amp;lt;/p&amp;gt;
&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;:Étape 3\nMettre à jour\n`SESSIONS_HISTORY.adoc`;
note right: Ligne récap : # / Date / Type / Sujet / Score&amp;lt;/p&amp;gt;
&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;:Étape 4\nMettre à jour\n`INDEX.adoc`;
note right: État courant, roadmap, fichiers modifiés&amp;lt;/p&amp;gt;
&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;:Étape 5\nMettre à jour\n`TEST_COVERAGE_ANALYSIS.adoc`;
note right: Si tests ajoutés ou modifiés&amp;lt;/p&amp;gt;
&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;:Étape 6\nMettre à jour\n`COMPLETED_TASKS_ARCHIVE.adoc`;
note right: Archiver tâches terminées&amp;lt;/p&amp;gt;
&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;:Afficher la checklist de confirmation;
note right: Vérifier que chaque [✅] est mérité&amp;lt;/p&amp;gt;
&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;stop
@enduml
----&amp;lt;/p&amp;gt;
&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;=== 150+セッションの結果&amp;lt;/p&amp;gt;
&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;これは、私の4つのプロジェクトに体系的に適用したこの手順の結果です：&amp;lt;/p&amp;gt;
&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;プラントUMLプラグイン&amp;lt;/strong&amp;gt; :&amp;lt;/p&amp;gt;
&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;* &amp;lt;strong&amp;gt;133セッション&amp;lt;/strong&amp;gt;プロジェクトの開始以来
* &amp;lt;strong&amp;gt;240/240 テスト合格&amp;lt;/strong&amp;gt;(100% カバレッジ)&amp;amp;#8201;&amp;amp;#8212;&amp;amp;#8201;EPICs 1-7 完了
* &amp;lt;strong&amp;gt;57 シナリオ Cucumber BDD&amp;lt;/strong&amp;gt;�検証済み
* 設定ファイルに関する実際のエラーから生じた安全規則 (Session 2 bakery-plugin)&amp;lt;/p&amp;gt;
&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;ベーカリープラグイン&amp;lt;/strong&amp;gt;:&amp;lt;/p&amp;gt;
&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;* &amp;lt;strong&amp;gt;11セッション&amp;lt;/strong&amp;gt;2週間で
* Supabase → Firebase の移行が完了（9つのテストが修正されました）
* EPIC 6 (publishProfile) 本番環境で機能する
* ルール 0 が作成されました :`publishToMavenLocal`各修正後の必須&amp;lt;/p&amp;gt;
&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;マジック・スティック&amp;lt;/strong&amp;gt;:&amp;lt;/p&amp;gt;
&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;* &amp;lt;strong&amp;gt;23セッション&amp;lt;/strong&amp;gt;A/Bパーティションを持つXubuntuライブシステムを構築するために
* セッション10で最初に生成されたISO
* QEMU + VNC の形式化されたブートテスト (LAZY ドキュメント 144 行)
* 機能的なSourceForgeのCI/CD&amp;lt;/p&amp;gt;
&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;cheroliv.com&amp;lt;/strong&amp;gt; :&amp;lt;/p&amp;gt;
&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;* &amp;lt;strong&amp;gt;9回の正式なセッション&amp;lt;/strong&amp;gt;+ 7回のプレシステムセッションの再構成
* 記事0101 (OpenCode PATH) 公開済み
* Article 0108（こちら）は、その欠点の分析後に書き直された
* 完全なガバナンスがMarkdownからAsciiDocに移行されました&amp;lt;/p&amp;gt;
&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;=== 最終チェックリスト&amp;lt;/p&amp;gt;
&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;6ステップのサイレント実行後に、エージェントは確認チェックリストを表示しなければなりません：&amp;lt;/p&amp;gt;
&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;----&amp;lt;/p&amp;gt;
&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;✅ Procédure de fin de session exécutée 📋 Checklist :&amp;lt;/p&amp;gt;
&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;絶対的なルール&amp;lt;/strong&amp;gt;どのステップもマークすることはできません`[✅]&amp;lt;code&amp;gt;ファイルが実際に変更され、検証されていない場合。&amp;lt;/p&amp;gt;
&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;== Bootstrapガイド：1日目、セッション0&amp;lt;/p&amp;gt;
&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;あなたはその方法に確信を持っています。新しいプロジェクトに適用したいです。どこから始めればよいでしょうか？&amp;lt;/p&amp;gt;
&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;私は2026年4月28日にこの瞬間を経験しました。私はOpencodeを開いて`jhipster-gradle-plugins&amp;lt;/code&amp;gt;, 私の JHipster Gradle プラグイン 2 つを含むモノレポです。これはすでに存在するプロジェクトで — コードはそこにあり、Gradle タスクは正常に動作しています。しかし、エージェントのガバナンスは？ゼロ。真っ白なページ。このように`plantuml-plugin`そのセッション1は、何ヶ月も前のことだった。&amp;lt;/p&amp;gt;
&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;以下が私が従った正確な手順であり、今後の新しいプロジェクトでも同じように従います。順序に注意してください — 重要です。&amp;lt;/p&amp;gt;
&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;[plantuml, format=svg, id=diag-bootstrap, alt=&amp;quot;Flux de bootstrap en 6 étapes pour initialiser la gouvernance agent sur un nouveau projet&amp;quot;]
----
@startuml
skinparam backgroundColor #FEFEFE
skinparam defaultTextAlignment center
skinparam wrapWidth 250
skinparam activityBackgroundColor #E8F5E9&amp;lt;/p&amp;gt;
&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;title ブートストラップ ガバナンス — 1日目, セッション0
start
:Étape 0\nCréer &amp;lt;strong&amp;gt;opencode.json&amp;lt;/strong&amp;gt;\n(6 lignes, instructions: AGENT.adoc);
note right: Le pont qui charge\nAGENT.adoc automatiquement&amp;lt;/p&amp;gt;
&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;:Étape 1\nCréer les dossiers\n&amp;lt;strong&amp;gt;mkdir -p .agents/sessions/ .agents/archives/&amp;lt;/strong&amp;gt;;
note right: Les conteneurs vides\navant que l&amp;amp;#8217;agent écrive dedans&amp;lt;/p&amp;gt;
&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;:Étape 2\nCréer &amp;lt;strong&amp;gt;AGENT.adoc&amp;lt;/strong&amp;gt;\n(200 lignes, règles absolues);
note right: Le fichier maître\nStructure minimale v1&amp;lt;/p&amp;gt;
&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;:Étape 3\nCréer &amp;lt;strong&amp;gt;PROMPT_REPRISE.adoc&amp;lt;/strong&amp;gt;\nMission session 1 (max 70 lignes);
note right: Ce que l&amp;amp;#8217;agent doit\nfaire à la prochaine session&amp;lt;/p&amp;gt;
&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;:Étape 4\nCréer &amp;lt;strong&amp;gt;.agents/INDEX.adoc&amp;lt;/strong&amp;gt;\nRègles exécutives + roadmap;
note right: Point d&amp;amp;#8217;entrée EAGER\ndans le dossier LAZY&amp;lt;/p&amp;gt;
&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;:Étape 5\nCréer les fichiers LAZY structurants\n6 fichiers : SESSIONS_HISTORY, CHECKLIST, etc.;
note right
  • SESSIONS_HISTORY.adoc
  • SESSION_CHECKLIST.adoc
  • PROCEDURES.adoc
  • AGENT_SESSION_MANAGER.adoc
  • TEST_COVERAGE_ANALYSIS.adoc
  • Agents spécialisés (si besoin)
end note&amp;lt;/p&amp;gt;
&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;:Étape 6\nAjouter le projet au Portefeuille\nMettre à jour TOUS les INDEX.adoc existants;
note right: Maintenance transverse\nObligatoire mais fastidieuse&amp;lt;/p&amp;gt;
&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;:✅ Bootstrap terminé\nSession 1 prête;
note right: 20 minutes investies\nDes centaines économisées&amp;lt;/p&amp;gt;
&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;stop
@enduml
----&amp;lt;/p&amp;gt;
&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;=== ステップ 0: &amp;lt;code&amp;gt;opencode.json&amp;lt;/code&amp;gt; を作成&amp;lt;/p&amp;gt;
&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;これは最初のファイルです。いいえ`AGENT.adoc`, ない`INDEX.adoc`。&amp;lt;code&amp;gt;opencode.json`まず、単純な理由で： あなたが作成するとき`AGENT.adoc`まず、自動的にロードするブリッジを作成するのを忘れるでしょう。私はそれを…で作りました。`bakery-plugin&amp;lt;/code&amp;gt;, 私は何を話しているか知っています。&amp;lt;/p&amp;gt;
&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;=== ステップ 1：フォルダーを作成する&amp;lt;/p&amp;gt;
&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;[source,bash]
----
mkdir -p .agents/sessions .agents/archives
----&amp;lt;/p&amp;gt;
&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;空のフォルダーが2つです。&amp;lt;code&amp;gt;sessions/`各セッションのアーカイブを受け取ります。`archives/`月次のCOMPLETED_TASKS_ARCHIVEを受け取ります。これらのフォルダは、エージェントが書き込む必要がある*前*に存在していなければなりません。フォルダとファイルを同時に作成しなければならないエージェントは、静かに失敗する可能性のあるエージェントです。&amp;lt;/p&amp;gt;
&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;=== ステップ 2: `AGENT.adoc&amp;lt;/code&amp;gt; を作成 — マスターファイル&amp;lt;/p&amp;gt;
&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;最初のバージョン用の最小構造（成長します）：&amp;lt;/p&amp;gt;
&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;[source]
----
= {NOM_PROJET} — Directives Agent&amp;lt;/p&amp;gt;
&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;[CAUTION]
----&amp;lt;/p&amp;gt;
&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;必須停止&amp;lt;/strong&amp;gt;rm の前に、 Write、削除 :&amp;lt;/p&amp;gt;
&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;1. ファイル全体を読む
2. 確認 git ls-files
3. 確認を求める
4. 待つ「はい」&amp;lt;/p&amp;gt;
&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;== プロジェクト&amp;lt;/p&amp;gt;
&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;名前&amp;lt;/strong&amp;gt;: &amp;amp;#8230;&amp;amp;#8203; &amp;lt;strong&amp;gt;スタック&amp;lt;/strong&amp;gt;: &amp;amp;#8230;&amp;amp;#8203; &amp;lt;strong&amp;gt;ドキュメンテーション&amp;lt;/strong&amp;gt;: AsciiDoc&amp;lt;/p&amp;gt;
&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;== 絶対的なルール&amp;lt;/p&amp;gt;
&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;=== 0. 開発環境&amp;lt;/p&amp;gt;
&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;必須のコマンド&amp;amp;#8230;&amp;amp;#8203;&amp;lt;/p&amp;gt;
&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;=== 1. COMMITS/GIT&amp;lt;/p&amp;gt;
&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;正式な禁止&amp;amp;#8230;&amp;amp;#8203;&amp;lt;/p&amp;gt;
&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;=== 1b. 設定ファイル — 絶対安全規則&amp;lt;/p&amp;gt;
&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;決して潰さないで&amp;amp;#8230;&amp;amp;#8203;&amp;lt;/p&amp;gt;
&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;=== 2. セッション終了時のテスト&amp;lt;/p&amp;gt;
&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;正式な禁止&amp;amp;#8230;&amp;amp;#8203;&amp;lt;/p&amp;gt;
&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;=== 3. セッション終了手順&amp;lt;/p&amp;gt;
&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;6つの必須ステップ&amp;amp;#8230;&amp;amp;#8203;&amp;lt;/p&amp;gt;
&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;== コンテキスト管理 — LAZY/EAGER&amp;lt;/p&amp;gt;
&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;Eager ファイル / Lazy ファイル&amp;amp;#8230;&amp;amp;#8203;&amp;lt;/p&amp;gt;
&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;この最小テンプレートはエージェントを起動させます。リッチ版 — プロジェクト構造、重要なコンポーネント、EPIC、バックログ — はセッション1で提供され、そのときエージェントはすでに基本ルールを手にしており、ドキュメントを充実させるお手伝いができます。&amp;lt;/p&amp;gt;
&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;=== ステップ 3 : 作成 &amp;lt;code&amp;gt;PROMPT_REPRISE.adoc&amp;lt;/code&amp;gt; — ミッション セッション 1&amp;lt;/p&amp;gt;
&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;「これはセッション1、ミッションはまだ定義されていません。」というファイル。最大70行、セッション0（ブートストラップの概要）セクションとセッション1（ユーザーと定義する優先順位）セクションを含む。&amp;lt;/p&amp;gt;
&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;=== ステップ 4: &amp;lt;code&amp;gt;.agents/INDEX.adoc&amp;lt;/code&amp;gt; を作成 — エントリーポイント&amp;lt;/p&amp;gt;
&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;絶対的なルール（実行版）およびセッションテーブルを含むファイル。ブートストラップのために、コンパクトな形式のルール0から3、プロジェクトポートフォリオ（新しいプロジェクトに絵文字🆕を含む）、そして入力待ちの空のロードマップをリストします。&amp;lt;/p&amp;gt;
&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;=== ステップ 5: LAZY構造ファイル作成&amp;lt;/p&amp;gt;
&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;順に：&amp;lt;/p&amp;gt;
&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;1. &amp;lt;code&amp;gt;.agents/SESSIONS_HISTORY.adoc&amp;lt;/code&amp;gt;— セッション0のみのテーブル
2. &amp;lt;code&amp;gt;.agents/SESSION_CHECKLIST.adoc&amp;lt;/code&amp;gt;―テンプレート「セッションを変更するタイミング」
3. &amp;lt;code&amp;gt;.agents/PROCEDURES.adoc&amp;lt;/code&amp;gt;— 6ステップの完全な手順 + EAGER/LAZY
4. &amp;lt;code&amp;gt;.agents/AGENT_SESSION_MANAGER.adoc&amp;lt;/code&amp;gt;— アーカイブのテンプレート
5. &amp;lt;code&amp;gt;.agents/TEST_COVERAGE_ANALYSIS.adoc&amp;lt;/code&amp;gt;— テスト追跡表、最初は空&amp;lt;/p&amp;gt;
&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;もしあなたのプロジェクトが複雑なビジネスドメインを持っている場合 （例えば`jhipster-gradle-plugins`その mono-repo persistence/assistant) 、 専門エージェントを今すぐ作成してください：&amp;lt;/p&amp;gt;
&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;1. &amp;lt;code&amp;gt;.agents/PLUGIN_DEVELOPER.adoc&amp;lt;/code&amp;gt;— コードの規約と依存関係の境界 (プラグインの場合)
2. &amp;lt;code&amp;gt;.agents/BACKLOG_MANAGER.adoc&amp;lt;/code&amp;gt;— 計画構造と特定されたリスク&amp;lt;/p&amp;gt;
&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;使わないエージェントを作らないでください。エンコードする具体的なルールのないエージェントは、汚染する死んだファイルです。&amp;lt;code&amp;gt;.agents/&amp;lt;/code&amp;gt;。&amp;lt;/p&amp;gt;
&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;=== ステップ 6: すべてのプロジェクトのポートフォリオにプロジェクトを追加&amp;lt;/p&amp;gt;
&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;これは必ず忘れてしまうステップです。それぞれ`INDEX.adoc`各プロジェクトには、すべてのプロジェクトを同じ方法論でリストする「プロジェクトポートフォリオ」という表が含まれます。新しいプロジェクトを作成する際には、以下を行う必要があります:&amp;lt;/p&amp;gt;
&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;1. 新しいプロジェクトのポートフォリオに行を追加する（論理）
2. 既存のすべてのプロジェクトのポートフォリオに一行を追加 — はい、すべて&amp;lt;/p&amp;gt;
&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;私の4（現在5つ）のプロジェクトでは、これは開けることを意味します`INDEX.adoc` de &amp;lt;code&amp;gt;magic-stick&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;bakery-gradle&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;cheroliv.com&amp;lt;/code&amp;gt;, `plantuml-gradle`それに行を追加する`jhipster-gradle-plugins&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;Session 1&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;amp;#8230;&amp;amp;#8203;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;2026-04-28 🆕&amp;lt;code&amp;gt;.&amp;lt;/p&amp;gt;
&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;面倒くさいです。手動です。これも、作業しているプロジェクトに関係なく、エージェントが他のプロジェクトの存在とその状態を知ることができるように保証する唯一の方法です。セッション 012 の`magic-stick&amp;lt;/code&amp;gt;, エージェントはポートフォリオで2つの不整合を検出しました —`bakery-gradle`彼の COMPLETED_TASKS_ARCHIVE が遅れていて、そして`plantuml-gradle`彼は、手順書（5ステップ）とインデックス（6ステップ）の間にずれがあった。このクロステーブルがなければ、これらの不整合は見えなかったままだっただろう。&amp;lt;/p&amp;gt;
&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;[plantuml, format=svg, id=diag-portfolio-graph, alt=&amp;quot;Graphe du portefeuille de projets — références croisées entre INDEX.adoc&amp;quot;]
----
@startuml
skinparam backgroundColor #FEFEFE
skinparam defaultTextAlignment center
skinparam nodeBackgroundColor #E3F2FD&amp;lt;/p&amp;gt;
&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;title プロジェクトポートフォリオ — 相互参照 INDEX.adoc
node &amp;quot;&amp;lt;strong&amp;gt;magic-stick&amp;lt;/strong&amp;gt;\nSession 037\nSCRIPT_VERIFICATION&amp;quot; as MS #E1BEE7
node &amp;quot;&amp;lt;strong&amp;gt;bakery-gradle&amp;lt;/strong&amp;gt;
セッション11
TEST_COVERAGE&amp;quot; as BG #FFE0B2
node &amp;quot;&amp;lt;strong&amp;gt;cheroliv.com&amp;lt;/strong&amp;gt;
セッション 10
TEST_COVERAGE&amp;quot; as CH #C8E6C9
node &amp;quot;&amp;lt;strong&amp;gt;plantuml-gradle&amp;lt;/strong&amp;gt;
セッション 133
TEST_COVERAGE&amp;quot; as PG #BBDEFB
node &amp;quot;&amp;lt;strong&amp;gt;jhipster-gradle&amp;lt;/strong&amp;gt;
セッション 1 🆕
テストカバレッジ&amp;quot; as JG #FFCDD2&amp;lt;/p&amp;gt;
&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;MS -&amp;amp;#8594; BG : INDEX.adoc référence
MS -&amp;amp;#8594; CH : INDEX.adoc référence
MS -&amp;amp;#8594; PG : INDEX.adoc référence
MS -&amp;amp;#8594; JG : INDEX.adoc référence 🆕&amp;lt;/p&amp;gt;
&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;BG -&amp;amp;#8594; MS : INDEX.adoc référence
BG -&amp;amp;#8594; CH : INDEX.adoc référence
BG -&amp;amp;#8594; PG : INDEX.adoc référence
BG -&amp;amp;#8594; JG : INDEX.adoc référence 🆕&amp;lt;/p&amp;gt;
&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;CH -&amp;amp;#8594; MS : INDEX.adoc référence
CH -&amp;amp;#8594; BG : INDEX.adoc référence
CH -&amp;amp;#8594; PG : INDEX.adoc référence
CH -&amp;amp;#8594; JG : INDEX.adoc référence 🆕&amp;lt;/p&amp;gt;
&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;PG -&amp;amp;#8594; MS : INDEX.adoc référence
PG -&amp;amp;#8594; BG : INDEX.adoc référence
PG -&amp;amp;#8594; CH : INDEX.adoc référence
PG -&amp;amp;#8594; JG : INDEX.adoc référence 🆕&amp;lt;/p&amp;gt;
&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;JG -&amp;amp;#8594; MS : INDEX.adoc référence
JG -&amp;amp;#8594; BG : INDEX.adoc référence
JG -&amp;amp;#8594; CH : INDEX.adoc référence
JG -&amp;amp;#8594; PG : INDEX.adoc référence&amp;lt;/p&amp;gt;
&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;note bottom of JG
  Quand on ajoute un projet :
  • 4 INDEX.adoc à mettre à jour
  • 1 ligne par portefeuille
  • Coût : 5 minutes
end note&amp;lt;/p&amp;gt;
&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;legend bottom&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;= Couleur&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;= Projet&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;amp;lt;#E1BEE7&amp;amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;magic-stick — ISO Linux live&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;amp;lt;#FFE0B2&amp;amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;bakery-gradle — Plugin JBake&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;amp;lt;#C8E6C9&amp;amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;cheroliv.com — Site personnel&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;amp;lt;#BBDEFB&amp;amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;plantuml-gradle — Plugin IA&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;amp;lt;#FFCDD2&amp;amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/tbody&amp;gt;
&amp;lt;/table&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;</description>
        </item><item>
            <title>なぜ `serve` は見苦しいサイトを表示していたのに、`publishSite` は完璧でした</title>
            <link >https://cheroliv.com/blog/2026/0107_jbake_serve_rendering_bug_fix_post.html</link>
            <pubDate>Wed, 22 Apr 2026 00:00:00 +0000</pubDate>
            <guid isPermaLink="false">blog/2026/0107_jbake_serve_rendering_bug_fix_post.html</guid>
            <description>&amp;lt;div id=&amp;quot;toc&amp;quot; class=&amp;quot;toc&amp;quot;&amp;gt;
&amp;lt;div id=&amp;quot;toctitle&amp;quot;&amp;gt;Table des matières&amp;lt;/div&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel1&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_シーン4つのスクリーンショット2つのレンダリング&amp;quot;&amp;gt;シーン：4つのスクリーンショット、2つのレンダリング&amp;lt;/a&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel2&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_ローカルレンダリング&amp;quot;&amp;gt;ローカルレンダリング&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_オンラインレンダリング&amp;quot;&amp;gt;オンラインレンダリング&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_診断_serve_は正しいフォルダを指していなかった&amp;quot;&amp;gt;診断 : &amp;lt;code&amp;gt;serve&amp;lt;/code&amp;gt; は正しいフォルダを指していなかった&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_根本的な原因jbake_cliはその通りに動作しない&amp;quot;&amp;gt;根本的な原因：JBake CLIはその通りに動作しない&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_解決策位置引数フラグではない&amp;quot;&amp;gt;解決策：位置引数、フラグではない&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_curlを使った素早い検証&amp;quot;&amp;gt;curlを使った素早い検証&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_なぜこのバグが厄介だったのか&amp;quot;&amp;gt;なぜこのバグが厄介だったのか&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_結論&amp;quot;&amp;gt;結論&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div id=&amp;quot;preamble&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;読了時間 : 10 minutes&amp;lt;/div&amp;gt;
&amp;lt;p&amp;gt;ローカルで自分のサイトが何も見えない瞬間を知っていますか？ でもオンラインにデプロイしたらすべてが完璧になる？ これは私の Gradle JBake プラグインで起きたことです。 タスク`serve`表示していたのは四角いボタン、黒い背景に黒いテキスト、そして奇妙に欠けているCSS。 しかし`publishSite`同じサイトを生成していましたが、それは完璧でした。問題の原因はCSSでもブラウザでもキャッシュでもなく、Kotlinのコードの1行と、コマンドライン引数の悪い習慣に起因していました。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;dlist&amp;quot;&amp;gt;
&amp;lt;dl&amp;gt;
&amp;lt;dt class=&amp;quot;hdlist1&amp;quot;&amp;gt;強迫性障害&amp;lt;/dt&amp;gt;
&amp;lt;dd&amp;gt;
&amp;lt;p&amp;gt;[]&amp;lt;/p&amp;gt;
&amp;lt;/dd&amp;gt;
&amp;lt;/dl&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_シーン4つのスクリーンショット2つのレンダリング&amp;quot;&amp;gt;シーン：4つのスクリーンショット、2つのレンダリング&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;それはシステムクラッシュの後のことだった。ローカルでのレンダリングを比較するために、スクリーンショットを4枚撮っていた（&amp;lt;code&amp;gt;./gradlew serve`上`localhost:8820&amp;lt;/code&amp;gt;) インラインレンダリングとともに (`publishSite`GitHub Pagesでは)。ページごとに2枚のスクリーンショット：上部と下部。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_ローカルレンダリング&amp;quot;&amp;gt;ローカルレンダリング&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;ページの上部&amp;lt;/strong&amp;gt;— ボタン &amp;lt;strong&amp;gt;Project&amp;lt;/strong&amp;gt; と &amp;lt;strong&amp;gt;Template&amp;lt;/strong&amp;gt; は&amp;lt;strong&amp;gt;小さくて長方形の&amp;lt;/strong&amp;gt;, 標準の色（青と緑）に。&amp;lt;strong&amp;gt;Start Writing&amp;lt;/strong&amp;gt; カードは　を持っている&amp;lt;strong&amp;gt;黒の単色背景&amp;lt;/strong&amp;gt;, フレームなし。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;imageblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;img src=&amp;quot;./images/screen_local1.png&amp;quot; alt=&amp;quot;Rendu local - haut de page&amp;quot;&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;ページ下部&amp;lt;/strong&amp;gt;— サブタイトル &amp;lt;strong&amp;gt;&amp;quot;Derniers articles et ressources&amp;lt;/strong&amp;gt;&amp;quot; は&amp;lt;strong&amp;gt;ほぼ判読不能&amp;lt;/strong&amp;gt;, 真っ黒い背景だと色が濃すぎます。ブログ画像の下の日付（「17 October 2013」など)は&amp;lt;strong&amp;gt;不在の&amp;lt;/strong&amp;gt;。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;imageblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;img src=&amp;quot;./images/screen_local2.png&amp;quot; alt=&amp;quot;Rendu local - bas de page&amp;quot;&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_オンラインレンダリング&amp;quot;&amp;gt;オンラインレンダリング&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;ページの上部&amp;lt;/strong&amp;gt;— 同じボタンは&amp;lt;strong&amp;gt;大きい, 羊, 派手なネオン緑&amp;lt;/strong&amp;gt;, 大文字のテキスト。地図には&amp;lt;strong&amp;gt;白い丸みのあるフレーム、ドロップシャドウ付き&amp;lt;/strong&amp;gt;。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;imageblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;img src=&amp;quot;./images/screen_online1.png&amp;quot; alt=&amp;quot;Rendu en ligne - haut de page&amp;quot;&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;ページ下部&amp;lt;/strong&amp;gt;— サブタイトルは&amp;lt;strong&amp;gt;読みやすい&amp;lt;/strong&amp;gt;. 日付は&amp;lt;strong&amp;gt;見える&amp;lt;/strong&amp;gt;. アイテムのカードは&amp;lt;strong&amp;gt;�丸い角&amp;lt;/strong&amp;gt;そして タイトルは&amp;lt;strong&amp;gt;太字&amp;lt;/strong&amp;gt;。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;imageblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;img src=&amp;quot;./images/screen_online2.png&amp;quot; alt=&amp;quot;Rendu en ligne - bas de page&amp;quot;&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;最初の反応：テーマ。私はダイナミックなテーマシステム（clair, sombre, high-contrast）を使用しています。それに基づいて`localStorage`. もしかしてローカルストアがハイコントラストテーマをトリガーしていたか？ いいえ。すでに書いていたhttps://cheroliv.com/blog/2025/0098_preloading_css_variable_post.html[テーマのプリロードに関する記事全体], 私はそれがどう動くか知っている。そして、ハイコントラスト モードでも、CSS構造（楕円形のボタン、シャドウ）はそこにあるべきだった。それはそこにはなかった。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;2番目の確認はブラウザキャッシュです。いいえ、クリーンなプロファイルでテストを行いました。差分は残っていました。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;第三の反射:`serve`同じファイルを提供していなかった`publishSite`.&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_診断_serve_は正しいフォルダを指していなかった&amp;quot;&amp;gt;診断 : &amp;lt;code&amp;gt;serve&amp;lt;/code&amp;gt; は正しいフォルダを指していなかった&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;私のGradleプラグイン`bakery`2つの主要なタスクがあります：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;code&amp;gt;bake&amp;lt;/code&amp;gt;: 静的サイトを生成します`build/bake/`&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;code&amp;gt;serve&amp;lt;/code&amp;gt;: ローカルウェブサーバーを起動&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;code&amp;gt;publishSite&amp;lt;/code&amp;gt;: 押す`build/bake/`GitHub Pagesへ&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;差異は…からしか来得ない`serve`. Si &amp;lt;code&amp;gt;publishSite`正しい内容を公開していた、それが`build/bake/`よかった。もし`serve`別のものを表示していたのは、それが役に立たなかったということだ。`build/bake/&amp;lt;/code&amp;gt;.&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;コードを見てみましょう。 中`SiteManager.kt`, タスク`serve`このように定義されています :&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;SiteManager.kt — La tâche serve (version buggy)&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-kotlin hljs&amp;quot; data-lang=&amp;quot;kotlin&amp;quot;&amp;gt;tasks.register(&amp;quot;serve&amp;quot;, JavaExec::class.java) { task -&amp;amp;gt;
    task.apply {
        mainClass.set(&amp;quot;org.jbake.launcher.Main&amp;quot;)
        classpath = jbakeRuntime
        environment(&amp;quot;GEM_PATH&amp;quot;, jbakeRuntime.asPath)
        jvmArgs(/* ... */)
        args = listOf(
            &amp;quot;-b&amp;quot;, file(site.bake.srcPath).absolutePath,
            &amp;quot;-s&amp;quot;, layout.buildDirectory.get()
                .asFile.resolve(site.bake.destDirPath)
                .absolutePath
        )
    }
}&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;code&amp;gt;org.jbake.launcher.Main`はJBake 2.7.0 CLIのエントリポイントです。 アイデア：通過&amp;lt;/code&amp;gt;-b`ソースフォルダと`-s`出力先フォルダーを指定し、サーバーモードを起動します。ただし、&amp;amp;#8230;&amp;amp;#8203;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_根本的な原因jbake_cliはその通りに動作しない&amp;quot;&amp;gt;根本的な原因：JBake CLIはその通りに動作しない&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;JBake 2.7.0 待っている des&amp;lt;strong&amp;gt;位置引数&amp;lt;/strong&amp;gt;ソースと宛先、続いてオプションのフラグ。シグニチャは：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-text hljs&amp;quot; data-lang=&amp;quot;text&amp;quot;&amp;gt;jbake &amp;amp;lt;source&amp;amp;gt; &amp;amp;lt;destination&amp;amp;gt; [options]&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;しかし、私のコードでは、次のように書いていました：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-text hljs&amp;quot; data-lang=&amp;quot;text&amp;quot;&amp;gt;args = listOf(&amp;quot;-b&amp;quot;, &amp;quot;/path/to/site&amp;quot;, &amp;quot;-s&amp;quot;, &amp;quot;/path/to/build/bake&amp;quot;)&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;JBakeはそれをこう解釈した：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;olist arabic&amp;quot;&amp;gt;
&amp;lt;ol class=&amp;quot;arabic&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;code&amp;gt;-b&amp;lt;/code&amp;gt;→ フラグ「bake」をパース（ブール値）、消費された&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;code&amp;gt;/path/to/site&amp;lt;/code&amp;gt;→ となる位置引数 1 (ソース)&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;code&amp;gt;-s&amp;lt;/code&amp;gt;→ フラグ &amp;#39;serve&amp;#39; (ブール型)をパースし、サーバーが起動&amp;lt;strong&amp;gt;すぐに&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;code&amp;gt;/path/to/build/bake&amp;lt;/code&amp;gt;→ それは孤立した議論となり、無視されたり誤解されたりする&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ol&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;結果 : JBake は取っていました`/path/to/site`ソースとして、&amp;lt;strong&amp;gt;目的地を考慮に入れていなかった&amp;lt;/strong&amp;gt;提供された (&amp;lt;code&amp;gt;build/bake&amp;lt;/code&amp;gt;), そしてそれはそのデフォルトディレクトリを使用していました（しばしば`./output`一時的なコピー). ファイル`css/styles.css`ビルドはしたがって上書きまたは無視され、カスタム変数も丸みも影もない古いデフォルトのCSSが提供されていた。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;比較すると`bake` et &amp;lt;code&amp;gt;publishSite`使用している&amp;lt;strong&amp;gt;公式のGradle JBakeプラグイン&amp;lt;/strong&amp;gt;(`jbake-gradle-plugin&amp;lt;/code&amp;gt;) きれいに書き込む`build/bake/`Gradle の API を通じて実行されます。CLI を経由しません。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_解決策位置引数フラグではない&amp;quot;&amp;gt;解決策：位置引数、フラグではない&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;修正は単純だ — 知ってしまえば。ソースとデスティネーションを位置引数として渡すだけです。その後`-s`最後に：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;SiteManager.kt — La tâche serve (version corrigée)&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-kotlin hljs&amp;quot; data-lang=&amp;quot;kotlin&amp;quot;&amp;gt;args = listOf(
    file(site.bake.srcPath).absolutePath,
    layout.buildDirectory.get()
        .asFile.resolve(site.bake.destDirPath)
        .absolutePath,
    &amp;quot;-s&amp;quot;
)&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;それだけです。3行変更され、バグが修正されました。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;プラグインをローカルで公開した後 (&amp;lt;code&amp;gt;publishToMavenLocal&amp;lt;/code&amp;gt;), un `./gradlew serve`JBakeを正しい構文で実行:&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-text hljs&amp;quot; data-lang=&amp;quot;text&amp;quot;&amp;gt;jbake /home/user/project/site /home/user/project/build/bake -s&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;そして今回は、JBakeに組み込まれたJettyサーバーが、内容をうまく提供しています。&amp;lt;code&amp;gt;build/bake/&amp;lt;/code&amp;gt;— オンラインで公開されているものと同じです。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
!define RECTANGLE class

package &amp;quot;前に (bug)&amp;quot; {
  RECTANGLE JBakeCLI1 {
    + args = [&amp;quot;-b&amp;quot;, &amp;quot;サイト&amp;quot;, &amp;quot;-s&amp;quot;, &amp;quot;ビルド/ベイク&amp;quot;]
  }

  RECTANGLE Source1 {
    + site/
  }

  RECTANGLE Dest1 {
    + ??? (dossier temporaire)
  }

  RECTANGLE Jetty1 {
    + sert mauvais fichiers
  }

  JBakeCLI1 --&amp;amp;gt; Source1 : lit
  JBakeCLI1 -[#red]x Dest1 : destination ignorée
  Jetty1 --&amp;amp;gt; Dest1 : sert
}

package &amp;quot;後（修正）&amp;quot; {
  RECTANGLE JBakeCLI2 {
    + args = [&amp;quot;サイト&amp;quot;, &amp;quot;ビルド/ベイク&amp;quot;, &amp;quot;-s&amp;quot;]
  }

  RECTANGLE Source2 {
    + site/
  }

  RECTANGLE Dest2 {
    + build/bake/
  }

  RECTANGLE Jetty2 {
    + sert les bons fichiers
  }

  JBakeCLI2 --&amp;amp;gt; Source2 : lit
  JBakeCLI2 --&amp;amp;gt; Dest2 : écrit dans
  Jetty2 --&amp;amp;gt; Dest2 : sert OK
}
@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_curlを使った素早い検証&amp;quot;&amp;gt;curlを使った素早い検証&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;サーバーが正しいコンテンツを提供していることを確認するため、シンプルな`curl`確認します`index.html`含む`data-bs-theme=&amp;quot;light&amp;quot;`そして`build/bake/css/styles.css`確かに31 402バイト — 生成されたファイルと同一である`bake`.&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;$ ./gradlew serve
# Dans un autre terminal :
$ curl -s http://localhost:8820/ | grep data-bs-theme
&amp;amp;lt;html ... data-bs-theme=&amp;quot;light&amp;quot; ...&amp;amp;gt;

$ curl -I http://localhost:8820/css/styles.css
HTTP/1.1 200 OK
Content-Length: 31402
Content-Type: text/css&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;ローカルレンダリングは現在&amp;lt;strong&amp;gt;同一ピクセル&amp;lt;/strong&amp;gt;デプロイされたレンダリングに。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_なぜこのバグが厄介だったのか&amp;quot;&amp;gt;なぜこのバグが厄介だったのか&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;なぜ捕まえるのが難しかったか、わかりますか？&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;olist arabic&amp;quot;&amp;gt;
&amp;lt;ol class=&amp;quot;arabic&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;明示的なエラーはありません&amp;lt;/strong&amp;gt;: JBakeはクラッシュしませんでした。それは単に間違ったフォルダで「動作していた」だけ。&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;ビルドは機能していた&amp;lt;/strong&amp;gt;:`./gradlew bake`正しくファイルを生成していた`build/bake/`.&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;デプロイメントが機能していました&amp;lt;/strong&amp;gt;:`publishSite`オンラインで良いコンテンツを推していた。&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;だけ &amp;lt;code&amp;gt;serve&amp;lt;/code&amp;gt; 壊れていた&amp;lt;/strong&amp;gt;: 開発タスク、つまり常に使ってイテレーションを行うもの&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;-key value`の習慣&amp;lt;/strong&amp;gt;: 開発者として、私たちは何年ものUnix CLIに条件付けられている (&amp;lt;code&amp;gt;-o output&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;-i input&amp;lt;/code&amp;gt;). JBake CLI は例外です — ソースとデスティネーションは位置引数です。&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ol&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_結論&amp;quot;&amp;gt;結論&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;JBake（または他のCLIツール）をラップするGradleプラグインをメンテナンスしている場合&amp;lt;strong&amp;gt;引数のドキュメントを読んでください&amp;lt;/strong&amp;gt;たとえあなたがそれらを知っていると思っていても。 暗黙の仮説 (&amp;lt;code&amp;gt;-s&amp;lt;/code&amp;gt;= &amp;quot;set destination&amp;quot;) これは視覚的なデバッグに何時間もかかる可能性があります。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;ここで、この修正は文字通りに変更することだった：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-text hljs&amp;quot; data-lang=&amp;quot;text&amp;quot;&amp;gt;args = listOf(&amp;quot;-b&amp;quot;, src, &amp;quot;-s&amp;quot;, dest)   // ❌ BUG&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;en :&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-text hljs&amp;quot; data-lang=&amp;quot;text&amp;quot;&amp;gt;args = listOf(src, dest, &amp;quot;-s&amp;quot;)         // ✅ FIX&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;3つのトークンが移動されただけで、私のローカルサイトは本番サイトと同じくらい美しくなりました。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;レッスン&amp;lt;/strong&amp;gt;: レンダリングがローカルと本番で理由なく異なる場合、まずまず &amp;lt;strong&amp;gt;pipeline&amp;lt;/strong&amp;gt; を疑う — CSSでもなく、ブラウザでもなく、ましてやフレームワークでもない。これはしばしば、レンダリング直前の手順がごまかしていることが多い。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;</description>
        </item><item>
            <title>OpenCode と 不完全な PATH : なぜあなたのツールはエージェントのシェルに存在しなかったのか</title>
            <link >https://cheroliv.com/blog/2026/0106_opencode_path_sdkman_nvm_post.html</link>
            <pubDate>Tue, 21 Apr 2026 00:00:00 +0000</pubDate>
            <guid isPermaLink="false">blog/2026/0106_opencode_path_sdkman_nvm_post.html</guid>
            <description>&amp;lt;div id=&amp;quot;toc&amp;quot; class=&amp;quot;toc&amp;quot;&amp;gt;
&amp;lt;div id=&amp;quot;toctitle&amp;quot;&amp;gt;Table des matières&amp;lt;/div&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel1&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_シーンツールの世界の中の盲目のエージェント&amp;quot;&amp;gt;シーン：ツールの世界の中の盲目のエージェント&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_バグの解剖2つのシェル2つの世界&amp;quot;&amp;gt;バグの解剖：2つのシェル、2つの世界&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_犯人_zshrc_vs_zshenv&amp;quot;&amp;gt;犯人 : &amp;lt;code&amp;gt;.zshrc&amp;lt;/code&amp;gt; vs `.zshenv&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_ステップバイステップ診断&amp;quot;&amp;gt;ステップバイステップ診断&amp;lt;/a&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel2&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_エージェントのpathを確認する&amp;quot;&amp;gt;エージェントのPATHを確認する&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_2_zshrcにあるが_zshenvにないものを特定する&amp;quot;&amp;gt;2. .zshrcにあるが.zshenvにないものを特定する&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_3_zshenv_が存在するか確認する&amp;quot;&amp;gt;3. .zshenv が存在するか確認する&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_解決策_zshenv_正しいパス&amp;quot;&amp;gt;解決策: .zshenv + 正しいパス&amp;lt;/a&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel2&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_すべての必須パスを含む_zshenv_を作成する&amp;quot;&amp;gt;すべての必須パスを含む .zshenv を作成する&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_zshenv_で_source_sdkman_init_sh_を使わないのはなぜですか&amp;quot;&amp;gt;.zshenv で &amp;lt;code&amp;gt;source sdkman-init.sh&amp;lt;/code&amp;gt; を使わないのはなぜですか？&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_nvmケース_バージョンマネージャーが痕跡を残すのを忘れたとき&amp;quot;&amp;gt;NVMケース： バージョンマネージャーが痕跡を残すのを忘れたとき&amp;lt;/a&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel2&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_nvmの問題&amp;quot;&amp;gt;NVMの問題&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_解決策nvm用にシンボリックリンク_current_を作成する&amp;quot;&amp;gt;解決策：NVM用にシンボリックリンク &amp;lt;code&amp;gt;current&amp;lt;/code&amp;gt; を作成する&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_シンボリックリンクのアップデートを自動化する&amp;quot;&amp;gt;シンボリックリンクのアップデートを自動化する&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_パスのサマリー表&amp;quot;&amp;gt;パスのサマリー表&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_罠と対策&amp;quot;&amp;gt;罠と対策&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_学んだ教訓&amp;quot;&amp;gt;学んだ教訓&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_最終確認&amp;quot;&amp;gt;最終確認&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_リンク&amp;quot;&amp;gt;リンク&amp;lt;/a&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel2&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_公式ドキュメント&amp;quot;&amp;gt;公式ドキュメント&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_言及されたツール&amp;quot;&amp;gt;言及されたツール&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_もっと進む&amp;quot;&amp;gt;もっと進む&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div id=&amp;quot;preamble&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;読了時間 : 13 minutes&amp;lt;/div&amp;gt;
&amp;lt;p&amp;gt;あなたはターミナルで OpenCode を起動し、すべてが機能します。エージェントは`gh`— 見つからない。一つ`java -version`不在. 一つ`node`— どこにもない。 しかし、これらのツールは &amp;lt;em&amp;gt;あなたの&amp;lt;/em&amp;gt; シェルに確かに存在します。問題？ OpenCode はシェルを起動します。&amp;lt;strong&amp;gt;非インタラクティブ&amp;lt;/strong&amp;gt;あなたを決して読まない`.zshrc`. ここで診断し、適切に修正する方法を示します。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;dlist&amp;quot;&amp;gt;
&amp;lt;dl&amp;gt;
&amp;lt;dt class=&amp;quot;hdlist1&amp;quot;&amp;gt;コン&amp;lt;/dt&amp;gt;
&amp;lt;dd&amp;gt;
&amp;lt;p&amp;gt;[]&amp;lt;/p&amp;gt;
&amp;lt;/dd&amp;gt;
&amp;lt;/dl&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_シーンツールの世界の中の盲目のエージェント&amp;quot;&amp;gt;シーン：ツールの世界の中の盲目のエージェント&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;それは火曜日の夜だった。私はそれをインストールしたばかりだった。https://opencode.ai[オープンコード], そのAIエージェントは私のコードの書き方を変えると約束していた。最初のテスト：彼にGitHubのリポジトリをリストするように頼む。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;$ opencode
&amp;amp;gt; Utilise gh pour lister mes repos
❌ bash: gh: command not found&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;変だ。`gh`端末で正常に動作していました。他のものを試してみます：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;&amp;amp;gt; Vérifie la version de Java
❌ bash: java: command not found&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;それから：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;&amp;amp;gt; Lance le build Gradle
❌ bash: gradle: command not found&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;Java, Gradle, Node,&amp;lt;code&amp;gt;gh&amp;lt;/code&amp;gt;— エージェントには何も見えなかった。 私の端末は、すべてを見ていた。 まるでエージェントと私が二つの並行世界に住んでいるかのようだ。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;理解するのに何時間も費やした。何時間`echo $PATH`, de &amp;lt;code&amp;gt;which java&amp;lt;/code&amp;gt;,苛立ちが増すなか、私はついに気付いた、問題はツールではなく — それは&amp;lt;strong&amp;gt;シェル&amp;lt;/strong&amp;gt;。OpenCodeは、サブプロセスを起動するようなエージェントのように、シェルで作業する&amp;lt;strong&amp;gt;非インタラクティブ&amp;lt;/strong&amp;gt;.そしてZshは、これらのシェルでは、純粋かつ単純にあなたを無視します`.zshrc`.&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;以下は、この診断、解決策、そして私が学んだ教訓の完全な物語です。AIエージェントを使用している場合 — OpenCode、Aider、Cursor、あるいはcronスクリプト — この問題はいずれあなたに関わってくるでしょう。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_バグの解剖2つのシェル2つの世界&amp;quot;&amp;gt;バグの解剖：2つのシェル、2つの世界&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;ターミナルを開くと、Zshはそれをシェルのように扱います。&amp;lt;strong&amp;gt;インタラクティブ&amp;lt;/strong&amp;gt;ロードする`.zshrc`, すべてを初期化します：SDKMAN, NVM, pnpm, エイリアス, 素敵なプロンプト。あなたの環境は完成しました。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;しかし、OpenCode がコマンドを実行するとき、インタラクティブなターミナルを起動しません。シェルを起動します。&amp;lt;strong&amp;gt;非インタラクティブ&amp;lt;/strong&amp;gt;— 人間が画面の後ろにいないタスクシェル。そしてZshはこの文脈ではジャンプする`.zshrc`. 彼はただ読むだけ`.zshenv`。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;なぜこの区別が存在するのでしょうか？なぜなら、非インタラクティブなシェルはスクリプトを実行するために設計されており、人間のユーザーにサービスを提供するためではないからです。バックグラウンドで動作するスクリプトにエイリアス、プロンプト、および補完をロードするのは無駄です。問題は、あなたの PATH — 実行可能ファイルを見つけるための最も重要な情報 — がしばしば初期化される場所にあるということです。&amp;lt;code&amp;gt;.zshrc&amp;lt;/code&amp;gt;, 中にない`.zshenv`。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
skinparam backgroundColor #FEFEFE

actor &amp;quot;あなた&amp;quot; as user
actor &amp;quot;OpenCode
(エージェント)&amp;quot; as agent
participant &amp;quot;シェル
対話型
(.zshrc がソースされました)&amp;quot; as ishell
participant &amp;quot;シェル
非対話的
(.zshrc 無視)&amp;quot; as nshell

user -&amp;amp;gt; ishell : gh, java, node ✅
agent -&amp;amp;gt; nshell : gh, java, node ❌

note right of ishell
  Source .zshrc :
  - SDKMAN init
  - NVM init
  - ~/apps dans PATH
  - pnpm dans PATH
end note

note right of nshell
  .zshrc ignoré !
  PATH = /usr/bin:/bin
  + quelques répertoires défaut
end note

@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;問題の根源：&amp;lt;strong&amp;gt;Zsh は &amp;lt;code&amp;gt;.zshrc&amp;lt;/code&amp;gt; を対話型シェルのみに対してソースします&amp;lt;/strong&amp;gt;. OpenCode, すべてのIAエージェントがサブプロセスを起動するように、非インタラクティブシェルを使用します。これらのシェルはただ読み取るだけ`.zshenv`。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_犯人_zshrc_vs_zshenv&amp;quot;&amp;gt;犯人 : &amp;lt;code&amp;gt;.zshrc&amp;lt;/code&amp;gt; vs `.zshenv&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;Zshは&amp;lt;strong&amp;gt;4つの初期化ファイル&amp;lt;/strong&amp;gt;、それぞれに特定の役割がある。エレガントなデザインだが、それが問題の核心でもある：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;table class=&amp;quot;tableblock frame-all grid-all stretch&amp;quot;&amp;gt;
&amp;lt;colgroup&amp;gt;
&amp;lt;col style=&amp;quot;width: 5%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 5%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 5%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 5%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 5%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 5%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 5%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 5%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 5%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 5%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 5%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 5%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 5%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 5%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 5%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 5%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 5%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 5%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 5%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 5%;&amp;quot;&amp;gt;
&amp;lt;/colgroup&amp;gt;
&amp;lt;tbody&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;ファイル&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;取得されたとき&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;役割&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;PATHを変更しますか？&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;code&amp;gt;.zshenv&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;常に&amp;lt;/strong&amp;gt;(インタラクティブ + ノンインタラクティブ + ログイン)&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;必須の環境変数、PATH&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;✅ はい — これは SA 場所&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;code&amp;gt;.zprofile&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;ログインシェルのみ&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;遅いコマンド（セッションごとに一度）&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;可能&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;code&amp;gt;.zshrc&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;インタラクティブシェルのみ&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;エイリアス, プロンプト, 補完, インタラクティブツール&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;�❌ 重要な変数には使用しないでください&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;code&amp;gt;.zlogin&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;ログインシェル（.zshrc の後）&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;ウェルカムメッセージ、最終化&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;めったに&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/tbody&amp;gt;
&amp;lt;/table&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;表は手がかりを与えるが、それを深く理解する必要がある。家の部屋のように考えてみてください：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;`.zshenv`は&amp;lt;strong&amp;gt;エントランスホール&amp;lt;/strong&amp;gt;— 誰もがそこに通る、訪問者でも住民でも。ここで何かを置けば、どのシェルでもそれを見ることができる。&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;`.zshrc`である&amp;lt;strong&amp;gt;居間&amp;lt;/strong&amp;gt;— ただ、インタラクティブなシェル（居住者）だけがそこに入る。訪問者（非インタラクティブなシェル）はロビーにとどまる。&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;code&amp;gt;.zprofile&amp;lt;/code&amp;gt; et `.zlogin`ログインシェル用の専用パーツです（SSHで接続するときなど）。&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;問題は、ほとんどの人が PATH をリビングに置いてしまうことだ。そして AI エージェントは、決してそこに入る権限を持たない。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;問題を図に示す：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
skinparam backgroundColor #FEFEFE

start

if (Shell interactif ?) then (Oui)
  :Source .zshenv;
  :Source .zprofile;
  :Source .zshrc;
  :Source .zlogin;
  note right
    SDKMAN ✅
    NVM ✅
    ~/apps ✅
    pnpm ✅
  end note
else (Non — shell non-interactif)
  :Source .zshenv uniquement;
  note right
    SDKMAN ❌
    NVM ❌
    ~/apps ❌
    pnpm ❌
  end note
endif

stop

@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;ターミナルを開くと、Zshは対話的です：それは読みます`.zshrc`, すべてが機能しています。 OpenCode がコマンドを実行するためにシェルを起動するとき、Zsh は非インタラクティブです：それはスキップします。&amp;lt;code&amp;gt;.zshrc&amp;lt;/code&amp;gt;, 読むのは`.zshenv`. Et si &amp;lt;code&amp;gt;.zshenv&amp;lt;/code&amp;gt; 存在しないまたは PATHを含まない — そこは砂漠だ。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;admonitionblock note&amp;quot;&amp;gt;
&amp;lt;table&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;icon&amp;quot;&amp;gt;
&amp;lt;i class=&amp;quot;fa icon-note&amp;quot; title=&amp;quot;Note&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;
&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;なぜ Zsh はそれをするのですか？&amp;lt;/strong&amp;gt;これはUnixから継承された設計上の選択です。非インタラクティブなシェルはなければならない&amp;lt;strong&amp;gt;速い&amp;lt;/strong&amp;gt; et &amp;lt;strong&amp;gt;再現可能&amp;lt;/strong&amp;gt;エイリアス、カラープロンプトとSDKMANの重い初期化をcronスクリプトまたはAIエージェントに読み込むと、遅くてもろいでしょう。したがって、分離は論理的：&amp;lt;code&amp;gt;.zshenv`主に (変数, PATH),&amp;lt;/code&amp;gt;.zshrc`� 快適さのために (aliases, prompt, 完了する)。問題は、本質を快適さの中に置くと発生します。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/table&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_ステップバイステップ診断&amp;quot;&amp;gt;ステップバイステップ診断&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;修正する前に、何が足りないのか正確に理解する必要があります。これが再現可能な診断方法です — AIエージェントと作業している場合は、これをお気に入りに保存してください。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_エージェントのpathを確認する&amp;quot;&amp;gt;エージェントのPATHを確認する&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;あなたは対話型ターミナルが見ているものと、非対話型シェルが見ているもの—つまり OpenCode が見ているもの—を比較します。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;# Dans votre terminal interactif (tout fonctionne)
echo $PATH | tr &amp;#39;:&amp;#39; &amp;#39;\n&amp;#39; | grep -v &amp;#39;^/usr&amp;#39; | sort&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;典型的な結果 :&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;/home/cheroliv/apps
/home/cheroliv/.nvm/versions/node/v22.19.0/bin
/home/cheroliv/.sdkman/candidates/java/current/bin
/home/cheroliv/.sdkman/candidates/gradle/current/bin
/home/cheroliv/.local/share/pnpm
/home/cheroliv/.local/bin&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;では、エージェントが見ているものをシミュレートしましょう — 対話型でないシェル :&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;# Shell non-interactif : pas de .zshrc
zsh -c &amp;#39;echo $PATH&amp;#39; | tr &amp;#39;:&amp;#39; &amp;#39;\n&amp;#39; | grep -v &amp;#39;^/usr&amp;#39; | sort&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;結果：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;/home/cheroliv/.local/bin&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;六つの道のうち五つが消えてしまった。&amp;lt;/strong&amp;gt;エージェントは環境の83%を失っている。それは、半分の調理器具しかない状態で料理をしろと言われているようなものです。水を沸かすことはできますが、それ以外はあまりできません。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;admonitionblock warning&amp;quot;&amp;gt;
&amp;lt;table&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;icon&amp;quot;&amp;gt;
&amp;lt;i class=&amp;quot;fa icon-warning&amp;quot; title=&amp;quot;Warning&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;
&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;コマンド`zsh -c &amp;#39;echo $PATH&amp;#39;`あなたの&amp;lt;strong&amp;gt;�診断ツール番号1&amp;lt;/strong&amp;gt;. あなたが日常的に使用しているツールが結果に含まれていない場合、あなたのAIエージェントもそれを見ることはできません。 これを各変更の前後でテストしてください`.zshenv`。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/table&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_2_zshrcにあるが_zshenvにないものを特定する&amp;quot;&amp;gt;2. .zshrcにあるが.zshenvにないものを特定する&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;今、私たちは犯人を探している 中`.zshrc`. 私たちのツールを参照している行をフィルタリングします：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;grep -n &amp;#39;apps\|SDKMAN\|NVM\|PNPM\|PATH&amp;#39; ~/.zshrc&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;典型的には：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;119: PATH=&amp;quot;/usr/bin/python3:$HOME/apps:$PATH&amp;quot;           # ← pas exporté !
171: export NVM_DIR=&amp;quot;$HOME/.nvm&amp;quot;
172: [ -s &amp;quot;$NVM_DIR/nvm.sh&amp;quot; ] &amp;amp;amp;&amp;amp;amp; \. &amp;quot;$NVM_DIR/nvm.sh&amp;quot;   # ← NVM init
176: nvm use --lts --silent                              # ← active une version
179: export PNPM_HOME=&amp;quot;/home/cheroliv/.local/share/pnpm&amp;quot;
187: export SDKMAN_DIR=&amp;quot;$HOME/.sdkman&amp;quot;
188: [[ -s &amp;quot;$HOME/.sdkman/bin/sdkman-init.sh&amp;quot; ]] &amp;amp;amp;&amp;amp;amp; source &amp;quot;$HOME/.sdkman/bin/sdkman-init.sh&amp;quot;&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;それは全部です&amp;lt;strong&amp;gt;不可視&amp;lt;/strong&amp;gt;OpenCodeのため。そして`PATH`行 119 のものでもない`export`é — 彼は決して現在のシェルを離れません。これは重要な技術的詳細です：変数がない`export`シェルが定義している場所にローカルのままです。 サブシェルは — OpenCodeによって起動されたもののように — それを決して継承しません。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_3_zshenv_が存在するか確認する&amp;quot;&amp;gt;3. .zshenv が存在するか確認する&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;cat ~/.zshenv 2&amp;amp;gt;/dev/null || echo &amp;quot;FICHIER ABSENT&amp;quot;&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;回答が「ファイルが見つからない」ならば、そこで勝負が決まる。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_解決策_zshenv_正しいパス&amp;quot;&amp;gt;解決策: .zshenv + 正しいパス&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;戦略はシンプルだが、精度が求められる：その中に入れる`.zshenv` &amp;lt;strong&amp;gt;のみ&amp;lt;/strong&amp;gt;� 必須のパスを、重い初期化スクリプトをソースせずに。移動しない`.zshrc`中に`.zshenv`— 本質を抽出します。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_すべての必須パスを含む_zshenv_を作成する&amp;quot;&amp;gt;すべての必須パスを含む .zshenv を作成する&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;`.zshenv`は&amp;lt;strong&amp;gt;唯一のファイル&amp;lt;/strong&amp;gt;Zshがソースすることを保証する中で&amp;lt;strong&amp;gt;みんな&amp;lt;/strong&amp;gt;コンテキスト。ここでPATHを設定すべきです。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;export SDKMAN_DIR=&amp;quot;$HOME/.sdkman&amp;quot;
export NVM_DIR=&amp;quot;$HOME/.nvm&amp;quot;
export PNPM_HOME=&amp;quot;$HOME/.local/share/pnpm&amp;quot;
export PATH=&amp;quot;$HOME/apps:$HOME/.sdkman/candidates/java/current/bin:$HOME/.sdkman/candidates/gradle/current/bin:$HOME/.nvm/current/bin:$PNPM_HOME:$HOME/.local/bin:$HOME/.local/share/JetBrains/Toolbox/scripts:/usr/bin/python3:$PATH&amp;quot;&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;admonitionblock note&amp;quot;&amp;gt;
&amp;lt;table&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;icon&amp;quot;&amp;gt;
&amp;lt;i class=&amp;quot;fa icon-note&amp;quot; title=&amp;quot;Note&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;
&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;使用します`$HOME/.nvm/current/bin`そしていいえ`$HOME/.nvm/versions/node/v22.19.0/bin`理由：Node のバージョンが変わります。ハードコーディングされたパスは次ので偽になります`nvm install`. 以下のセクションで詳しく説明します。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/table&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_zshenv_で_source_sdkman_init_sh_を使わないのはなぜですか&amp;quot;&amp;gt;.zshenv で &amp;lt;code&amp;gt;source sdkman-init.sh&amp;lt;/code&amp;gt; を使わないのはなぜですか？&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;最も誘惑的なアプローチは、単純に再現するで`.zshenv`そこで私たちがすること`.zshrc`— ソースする 初期化スクリプト。 On&amp;lt;strong&amp;gt;できる&amp;lt;/strong&amp;gt;したくなる :&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;# ❌ MAUVAISE IDÉE
[[ -s &amp;quot;$HOME/.sdkman/bin/sdkman-init.sh&amp;quot; ]] &amp;amp;amp;&amp;amp;amp; source &amp;quot;$HOME/.sdkman/bin/sdkman-init.sh&amp;quot;&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;問題 :&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;遅い&amp;lt;/strong&amp;gt;:`sdkman-init.sh`ネットワークの解決と各シェルでの検証を行います。非インタラクティブなシェルでは、これは無駄なコストです。&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;�壊れやすい&amp;lt;/strong&amp;gt;SDKMAN は対話的なコンテキストを期待します。その初期化はパイプやサブシェルでは無音で失敗する可能性があります。&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;無駄な&amp;lt;/strong&amp;gt;: SDKMANはその候補者を配置します`~/.sdkman/candidates/&amp;amp;lt;tool&amp;amp;gt;/current/bin`— アクティブなバージョンを指す安定したシンボリックリンクです。 これらを使用できます&amp;lt;strong&amp;gt;直接的に&amp;lt;/strong&amp;gt;。&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;良いアプローチ：SDKMANの初期化を回避し、シンボリックリンクを直接指す`current`. これはすべての解決策の鍵 :&amp;lt;strong&amp;gt;初期化コードではなく、ファイル構造を契約として使用する&amp;lt;/strong&amp;gt;。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
skinparam backgroundColor #FEFEFE

rectangle &amp;quot;ゆっくりとしたアプローチ
(source sdkman-init.sh)&amp;quot; as slow {
  card &amp;quot;.zshenv source sdkman-init.sh
シェルごとに2-3秒
ネットワークチェック
失敗のリスク&amp;quot; as s1 #FDEDEC
}

rectangle &amp;quot;�迅速なアプローチ
(直接シンボリックリンク)&amp;quot; as fast {
  card &amp;quot;.zshenv export PATH=...current/bin
0 ms
ネットワークなし
初期化なし&amp;quot; as s2 #E8F8E8
}

slow --&amp;amp;gt; fast : Même résultat final\nLe PATH pointe sur current/bin\ndans les deux cas

@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_nvmケース_バージョンマネージャーが痕跡を残すのを忘れたとき&amp;quot;&amp;gt;NVMケース： バージョンマネージャーが痕跡を残すのを忘れたとき&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_nvmの問題&amp;quot;&amp;gt;NVMの問題&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;調査が私を最も遠くまで導いたのはここだ。SDKMANはエレガントなデザインを持っています：すると`sdk install java 25.0.2-tem`, シンボリックリンクを作成します :&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;~/.sdkman/candidates/java/current -&amp;amp;gt; ~/.sdkman/candidates/java/25.0.2-tem&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;このシンボリックリンクは&amp;lt;strong&amp;gt;常に最新&amp;lt;/strong&amp;gt;その中を指してください`.zshenv`そしてあなたはカバーされています、どのシェルでも。 美しい。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;NVM、彼、作らない&amp;lt;strong&amp;gt;何も&amp;lt;/strong&amp;gt;そのような。シンボリックリンクはありません`current`. 安定したアンカーポイントはありません。 ハードコードされたバージョン管理されたパスを指す必要があり、これがその見た目です :&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;~/.nvm/versions/node/v22.19.0/bin/node&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;次の`nvm install 24`, この道は死んでいます。 あなたの`.zshenv`アクティブでなくなったバージョンを指します。これは時限爆弾です。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;admonitionblock note&amp;quot;&amp;gt;
&amp;lt;table&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;icon&amp;quot;&amp;gt;
&amp;lt;i class=&amp;quot;fa icon-note&amp;quot; title=&amp;quot;Note&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;
&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;NVMはなぜそれをするのですか？&amp;lt;/strong&amp;gt;NVMはPATHを動的に変更することで動作する毎`nvm use`. これは、バージョンを頻繁に変更する開発者向けに設計されています。インタラクティブなシェルで。シンボリックリンク`current`初期の仕様には含まれていませんでした — これは設計の見落としであり、自分たちで修正します。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/table&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
skinparam backgroundColor #FEFEFE

package &amp;quot;SDKMAN ✅&amp;quot; {
  [~/.sdkman/candidates/java/current] as sdk_current
  [~/.sdkman/candidates/java/25.0.2-tem/] as java_25
  [~/.sdkman/candidates/java/21.0.7-tem/] as java_21

  sdk_current --&amp;amp;gt; java_25 : symlink
}

package &amp;quot;NVM ❌ (修正前)&amp;quot; as nvm_before {
  [~/.nvm/versions/node/v22.19.0/] as node_22
  [~/.nvm/versions/node/v20.16.0/] as node_20
  note right of node_22
    Pas de symlink current !
    .zshenv doit pointer en dur
    Cassé au prochain nvm install
  end note
}

package &amp;quot;NVM ✅ (修正後)&amp;quot; as nvm_after {
  [~/.nvm/current] as nvm_current
  [~/.nvm/versions/node/v22.19.0/] as node_22b
  [~/.nvm/versions/node/v20.16.0/] as node_20b

  nvm_current --&amp;amp;gt; node_22b : symlink\n(mis à jour auto)
}

@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_解決策nvm用にシンボリックリンク_current_を作成する&amp;quot;&amp;gt;解決策：NVM用にシンボリックリンク &amp;lt;code&amp;gt;current&amp;lt;/code&amp;gt; を作成する&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;NVMがそれをしないので、私たちが自分たちでやります。原則は`SDKMAN`と同じ — シンボリックリンクです`current`常にアクティブなバージョンを指している。これを一度作成し、それから自動化して自分で更新されるようにする。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;# Créer le symlink initial
ln -sfn &amp;quot;$HOME/.nvm/versions/node/v22.19.0&amp;quot; &amp;quot;$HOME/.nvm/current&amp;quot;&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;今、中に`.zshenv`、使用します：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;$HOME/.nvm/current/bin&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;よりも：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;# ❌ Chemin en dur — cassé au prochain changement de version
$HOME/.nvm/versions/node/v22.19.0/bin&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_シンボリックリンクのアップデートを自動化する&amp;quot;&amp;gt;シンボリックリンクのアップデートを自動化する&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;シンボリックリンクは、アップデートしない場合、何の価値もありません。シンボリックリンク`current`それを行うときにアップデートする必要がある`nvm use` ou &amp;lt;code&amp;gt;nvm install&amp;lt;/code&amp;gt;. 解決策：1&amp;lt;strong&amp;gt;ラッパー&amp;lt;/strong&amp;gt;— 本当のコマンドをラップする関数`nvm`そして、各呼び出し後にシンボリックリンクを更新します。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;# À la fin de .zshrc, APRÈS le chargement de NVM
nvm use --lts --silent
ln -sfn &amp;quot;$(nvm_version_path &amp;quot;$(nvm current)&amp;quot;)&amp;quot; &amp;quot;$NVM_DIR/current&amp;quot;

_nvm() {
  command nvm &amp;quot;$@&amp;quot;
  local rc=$?
  ln -sfn &amp;quot;$(nvm_version_path &amp;quot;$(nvm current)&amp;quot;)&amp;quot; &amp;quot;$NVM_DIR/current&amp;quot;
  return $rc
}
alias nvm=&amp;#39;_nvm&amp;#39;&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;詳しく説明すると、どのように機能するか：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
skinparam backgroundColor #FEFEFE

actor Développeur
participant &amp;quot;nvm wrapper
(_nvm)&amp;quot; as wrapper
participant &amp;quot;nvm 実
(コマンド nvm)&amp;quot; as realnvm
participant &amp;quot;~/.nvm/current\n(シンボリックリンク)&amp;quot; as symlink

Développeur -&amp;amp;gt; wrapper : nvm use 20
wrapper -&amp;amp;gt; realnvm : command nvm use 20
realnvm --&amp;amp;gt; wrapper : version activée
wrapper -&amp;amp;gt; symlink : ln -sfn .../v20.16.0 ~/.nvm/current
wrapper --&amp;amp;gt; Développeur : retour

note right of symlink
  Toujours à jour !
  Utilisé par .zshenv
  → accessible par OpenCode
end note

@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;ワラッパー`_nvm`本物のコマンドを呼び出す`nvm`, その後シンボリックリンクを更新します。エイリアス`nvm=&amp;#39;_nvm&amp;#39;`入力するときにそうなるようにする`nvm`, wrapperを経由します。 シェルの初期化時に同様にその後も行います。&amp;lt;code&amp;gt;nvm use --lts&amp;lt;/code&amp;gt;。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;admonitionblock tip&amp;quot;&amp;gt;
&amp;lt;table&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;icon&amp;quot;&amp;gt;
&amp;lt;i class=&amp;quot;fa icon-tip&amp;quot; title=&amp;quot;Tip&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;
&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;`nvm_version_path`はNVMの内部関数で、バージョンのフルパスを解決します。これにより、パスを手動で再構築する必要がなくなります。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/table&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_パスのサマリー表&amp;quot;&amp;gt;パスのサマリー表&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;罠に移る前に、変換のビジュアルサマリー。左側に、あなたが持っていたもの（すべて`.zshrc`, エージェントに見えない)。 右側、あなたが今持っているもの (必須のパスの中の`.zshenv`, どこでも見える)&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;table class=&amp;quot;tableblock frame-all grid-all stretch&amp;quot;&amp;gt;
&amp;lt;colgroup&amp;gt;
&amp;lt;col style=&amp;quot;width: 25%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 25%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 25%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 25%;&amp;quot;&amp;gt;
&amp;lt;/colgroup&amp;gt;
&amp;lt;thead&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;th class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;ツール&amp;lt;/th&amp;gt;
&amp;lt;th class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;前 (.zshrc だけ)&amp;lt;/th&amp;gt;
&amp;lt;th class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;その後 (.zshenv + symlink)&amp;lt;/th&amp;gt;
&amp;lt;th class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;OpenCodeによって表示されますか？&amp;lt;/th&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/thead&amp;gt;
&amp;lt;tbody&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;`~/apps`python s = input() print(s, end=&amp;#39;&amp;#39;)&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;.zshrcでPATHがエクスポートされていない&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;code&amp;gt;$HOME/apps&amp;lt;/code&amp;gt;.zshenvの中&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;�✅&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;SDKMAN Java&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;code&amp;gt;sdkman-init.sh&amp;lt;/code&amp;gt;.zshrc でソースされている&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;code&amp;gt;$HOME/.sdkman/candidates/java/current/bin&amp;lt;/code&amp;gt;.zshenv内&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;�✅&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;SDKMAN Gradle&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;code&amp;gt;sdkman-init.sh&amp;lt;/code&amp;gt;.zshrc でソースされている&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;code&amp;gt;$HOME/.sdkman/candidates/gradle/current/bin&amp;lt;/code&amp;gt;.zshenv内で&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;(This response is intentionally left blank.)&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;NVM ノード&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;code&amp;gt;nvm use --lts&amp;lt;/code&amp;gt;.zshrcの中に&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;code&amp;gt;$HOME/.nvm/current/bin&amp;lt;/code&amp;gt;.zshenv (symlink)の中に&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;✅&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;pnpm&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;code&amp;gt;$PNPM_HOME&amp;lt;/code&amp;gt;.zshrc に&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;code&amp;gt;$PNPM_HOME&amp;lt;/code&amp;gt;.zshenvの中で&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;✅&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;JetBrains ツールボックス&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;Toolbox によって .zshrc に自動的に追加されました&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;code&amp;gt;$HOME/.local/share/JetBrains/Toolbox/scripts&amp;lt;/code&amp;gt;.zshenv 内&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;✅&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;Python 3&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;`/usr/bin/python3`PATH .zshrc内&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;明示的に .zshenv で&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;✅&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/tbody&amp;gt;
&amp;lt;/table&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_罠と対策&amp;quot;&amp;gt;罠と対策&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;このアプローチではすべてが完璧ではない。私が遭遇した問題と、それを回避する方法を示します。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;table class=&amp;quot;tableblock frame-all grid-all stretch&amp;quot;&amp;gt;
&amp;lt;colgroup&amp;gt;
&amp;lt;col style=&amp;quot;width: 33.3333%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 33.3333%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 33.3334%;&amp;quot;&amp;gt;
&amp;lt;/colgroup&amp;gt;
&amp;lt;thead&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;th class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;�罠&amp;lt;/th&amp;gt;
&amp;lt;th class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;説明&amp;lt;/th&amp;gt;
&amp;lt;th class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;軽減&amp;lt;/th&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/thead&amp;gt;
&amp;lt;tbody&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;PATH が重複&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;もし.zshenv と .zshrc が同じパスを追加すると、それが二回表示されます&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;`.zshenv`出典が明記されている&amp;lt;strong&amp;gt;前&amp;lt;/strong&amp;gt;.zshrc. 両方ともインタラクティブシェルで読み込まれます。PATHが重複することがあります。これは見た目の問題で、機能的ではありません。これを避けるには、デフォルトのPATHに含まれていない_absents_なパスだけを.zshenvに記述してください。&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;NVM : &amp;lt;code&amp;gt;.zshenv&amp;lt;/code&amp;gt; にハードコードされたバージョン&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;置く`~/.nvm/versions/node/v22.19.0/bin`ハードコードは次の段階で偽になる`nvm install`&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;シンボリックリンクを使用する`$HOME/.nvm/current/bin`+ ラッパー`_nvm`.zshrcの中&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;SDKMAN : .zshenv で sdkman-init.sh を source する&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;�遅い、脆い、非対話シェルでは役に立たない&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;シンボリックリンクを使用する`candidates/&amp;amp;lt;tool&amp;amp;gt;/current/bin`直接に&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;変更後のエイリアスが不足&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;ラッパー`nvm=&amp;#39;_nvm&amp;#39;`.zshrcの変更は、再読み込み後にのみ反映されます&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;シェルを再起動するまたは`source ~/.zshrc`&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;OpenCode は変更を検出していません&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;エージェントはすでに古い .zshenv を使ってそのサブシェルを起動しています&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;OpenCodeの.zshenvを変更後に再起動する&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;.zshenv が重すぎる&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;.zshenv に重い関数や対話型の初期化を置く&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;.zshenv = 環境変数とPATH のみ。なし`source`, 重い関数はなく、プロンプトもありません。&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/tbody&amp;gt;
&amp;lt;/table&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_学んだ教訓&amp;quot;&amp;gt;学んだ教訓&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;olist arabic&amp;quot;&amp;gt;
&amp;lt;ol class=&amp;quot;arabic&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;.zshrc` はインタラクティブです、&amp;lt;code&amp;gt;.zshenv&amp;lt;/code&amp;gt; は普遍的です。&amp;lt;/strong&amp;gt;— 変数が &amp;lt;em&amp;gt;すべて&amp;lt;/em&amp;gt; のシェル（AIエージェント、cron、スクリプト、IDE）に存在する必要がある場合、それはに入ります`.zshenv`リビングは快適ですが、エントランスホールは誰もが通る唯一の場所です。&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;バージョンマネージャーは等しくない&amp;lt;/strong&amp;gt;SDKMANはシンボリックリンクを作成する`current`設計によるものです。 NVM ではない。 このギャップを手動で埋める必要があります。 これは重要な教訓です：PATHを設定する前に、あなたのマネージャーが安定した固定ポイントを提供しているか確認してください。&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;.zshenv 内で init スクリプトをソースしないでください&amp;lt;/strong&amp;gt;—&amp;lt;code&amp;gt;sdkman-init.sh&amp;lt;/code&amp;gt; et `nvm.sh`インタラクティブなシェルのために設計されています。 非インタラクティブなコンテキストでは遅くて脆弱です。 シンボリックリンクは`current`十分で、即座です。&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;常に非インタラクティブなシェルでテストする&amp;lt;/strong&amp;gt;—`zsh -c &amp;#39;echo $PATH&amp;#39;`エージェントが見るものを正確にシミュレートします。 これは検証テストです。 このテストがなければ、エージェントに対して構成が機能しているかどうか分かりません。&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;Wrapperパターンは再利用可能です&amp;lt;/strong&amp;gt;— 同じパターン`_nvm`+`alias nvm=&amp;#39;_nvm&amp;#39;`これは、PATHを動的に変更し、安定した痕跡を残さないすべてのツールに適用されます。 これはあなたのアイデアボックスに追加されるもう一つのツールです。&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ol&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
skinparam backgroundColor #FEFEFE

rectangle &amp;quot;前&amp;quot; as avant {
  card &amp;quot;対話型シェル : ✅\n非対話型シェル : ❌\nOpenCode : ❌\nCron : ❌\nScripts : ❌&amp;quot; as av1 #FDEDEC
}

rectangle &amp;quot;後&amp;quot; as apres {
  card &amp;quot;対話型シェル : ✅
非対話型シェル : ✅
OpenCode : ✅
Cron : ✅
スクリプト : ✅&amp;quot; as ap1 #E8F8E8
}

avant --&amp;amp;gt; apres : .zshenv +\nsymlink ~/.nvm/current

@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_最終確認&amp;quot;&amp;gt;最終確認&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;作成した後`.zshenv`そして NVM シンボリックリンク、すべてが正常に動作することを確認してください — 両方のコンテキストで:&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;# Shell interactif (votre terminal)
gh --version &amp;amp;amp;&amp;amp;amp; java -version &amp;amp;amp;&amp;amp;amp; node --version&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;# Shell non-interactif (simulation OpenCode)
zsh -c &amp;#39;gh --version &amp;amp;amp;&amp;amp;amp; java -version &amp;amp;amp;&amp;amp;amp; node --version&amp;#39;&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;両方とも成功しなければなりません。はいの場合、あなたのAIエージェントはあなたと同じツールを見ることになります。いいえの場合、ステップバイステップの診断に戻ってください — おそらくパスを忘れたか、NVMのシンボリックリンクが古いです。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;admonitionblock tip&amp;quot;&amp;gt;
&amp;lt;table&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;icon&amp;quot;&amp;gt;
&amp;lt;i class=&amp;quot;fa icon-tip&amp;quot; title=&amp;quot;Tip&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;
&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;このテストを自動化してください。&amp;lt;/strong&amp;gt;このチェックを、ツールを更新するたびに実行するヘルスチェックスクリプトに追加してください。Un`zsh -c &amp;#39;which java &amp;amp;amp;&amp;amp;amp; which node &amp;amp;amp;&amp;amp;amp; which gh&amp;#39;`CIでは、これは驚きに対する保険です。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/table&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;em&amp;gt;&amp;lt;em&amp;gt;_ 非対話型シェルは、無言のゲストのようになります：それは玄関に表示されているものだけを読みます。PATH がリビングにある場合、それは決してそれを見ることはありません。 &amp;lt;/em&amp;gt;_&amp;lt;/em&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_リンク&amp;quot;&amp;gt;リンク&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_公式ドキュメント&amp;quot;&amp;gt;公式ドキュメント&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;https://zsh.sourceforge.io/Doc/Release/Files.html&amp;quot;&amp;gt;Zshドキュメント : スタートアップファイル&amp;lt;/a&amp;gt;Zshの初期化ファイルに関する公式リファレンスです。そこですべてが説明されていますが、しばしば忘れられがちです。&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;https://opencode.ai/docs/config/&amp;quot;&amp;gt;OpenCode : 設定&amp;lt;/a&amp;gt;— OpenCodeおよびその実行環境の設定方法。&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_言及されたツール&amp;quot;&amp;gt;言及されたツール&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;https://github.com/nvm-sh/nvm&amp;quot;&amp;gt;GitHub 上の NVM&amp;lt;/a&amp;gt;— Node Version Manager. Node.jsバージョン管理。&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;https://sdkman.io&amp;quot;&amp;gt;SDKMAN — 公式サイト&amp;lt;/a&amp;gt;— SDKMAN! JVM（Java、Kotlin、Gradleなど）用のバージョン管理ツール&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;https://sdkman.io/install&amp;quot;&amp;gt;SDKMAN : インストール&amp;lt;/a&amp;gt;— SDKMAN インストールガイド&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;https://cli.github.com&amp;quot;&amp;gt;gh` — GitHub コマンドラインインターフェース&amp;lt;/a&amp;gt;— GitHubのコマンドラインツール、あらゆる開発者に不可欠です。&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;https://gradle.org&amp;quot;&amp;gt;Gradle — 公式サイト&amp;lt;/a&amp;gt;— SDKMANを使ってインストールしているビルドシステム&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;https://pnpm.io&amp;quot;&amp;gt;pnpm — 公式サイト&amp;lt;/a&amp;gt;— 高速で省スペースなNode.jsパッケージマネージャー。&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;https://www.jetbrains.com/toolbox-app/&amp;quot;&amp;gt;JetBrains Toolbox&amp;lt;/a&amp;gt;— JetBrainsのIDE管理者、そのスクリプトをPATHに追加します。&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_もっと進む&amp;quot;&amp;gt;もっと進む&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;https://blog.andy2003.org/posts/2022/zsh-dotfiles/&amp;quot;&amp;gt;Zsh dotfiles: 完全ガイド&amp;lt;/a&amp;gt;— Zshのdotfiles管理についての詳しい記事&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;https://wiki.archlinux.org/title/Zsh&amp;quot;&amp;gt;ArchWikiのZsh&amp;lt;/a&amp;gt;— Zshの優れたコミュニティドキュメントの一つ。&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;https://github.com/nvm-sh/nvm/issues&amp;quot;&amp;gt;NVM の GitHub の Issue&amp;lt;/a&amp;gt;— シンボリックリンク周辺の議論を見るには`current`およびPATHの問題があります。&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;</description>
        </item><item>
            <title>Gradle ワークフローに Graphify を統合する：Knowledge Graph から PlantUML ダイアグラムまでを 1 つのコマンドで</title>
            <link >https://cheroliv.com/blog/pilot-batch/0105_integrer_graphify_workflow_gradle_post.html</link>
            <pubDate>Sun, 19 Apr 2026 00:00:00 +0000</pubDate>
            <guid isPermaLink="false">blog/pilot-batch/0105_integrer_graphify_workflow_gradle_post.html</guid>
            <description>&amp;lt;div id=&amp;quot;toc&amp;quot; class=&amp;quot;toc&amp;quot;&amp;gt;
&amp;lt;div id=&amp;quot;toctitle&amp;quot;&amp;gt;Table des matières&amp;lt;/div&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel1&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_問題コードに常に遅れを取る図表&amp;quot;&amp;gt;問題：コードに常に遅れを取る図表&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_解決策決定論的なknowledge_graph_plantumlパイプライン&amp;quot;&amp;gt;解決策：決定論的なKnowledge Graph → PlantUMLパイプライン&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_ステップ_1_graphifyをインストールしナレッジグラフを抽出する&amp;quot;&amp;gt;ステップ 1: Graphifyをインストールし、ナレッジグラフを抽出する&amp;lt;/a&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel2&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_インストール&amp;quot;&amp;gt;インストール&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_除外を設定する&amp;quot;&amp;gt;除外を設定する&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_knowledge_graphを抽出する&amp;quot;&amp;gt;Knowledge Graphを�抽出する&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_ステップ_2gradleプラグインがknowledge_graphをplantumlに変換します&amp;quot;&amp;gt;ステップ 2：GradleプラグインがKnowledge GraphをPlantUMLに変換します&amp;lt;/a&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel2&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_パイプラインアーキテクチャ&amp;quot;&amp;gt;パイプラインアーキテクチャ&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_内部コンポーネント&amp;quot;&amp;gt;内部コンポーネント&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_レンダリングルール&amp;quot;&amp;gt;レンダリングルール&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_ステップ3日常での使用&amp;quot;&amp;gt;ステップ3：日常での使用&amp;lt;/a&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel2&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_完全図&amp;quot;&amp;gt;完全図&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_コミュニティで絞り込む&amp;quot;&amp;gt;コミュニティで絞り込む&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_エッジの種類でフィルタリング&amp;quot;&amp;gt;エッジの種類でフィルタリング&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_ノードの種類と信頼度でフィルター&amp;quot;&amp;gt;ノードの種類と信頼度でフィルター&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_カスタム出力ディレクトリ&amp;quot;&amp;gt;カスタム出力ディレクトリ&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_プロパティの完全な参照&amp;quot;&amp;gt;プロパティの完全な参照&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_gradle_ワークフローにおける完全なパイプライン&amp;quot;&amp;gt;Gradle ワークフローにおける完全なパイプライン&amp;lt;/a&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel2&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_ワークフローのタイプ&amp;quot;&amp;gt;ワークフローのタイプ&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_開発サイクルへの統合&amp;quot;&amp;gt;開発サイクルへの統合&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_インクリメンタルアップデート&amp;quot;&amp;gt;インクリメンタルアップデート&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_ドッグフィーディング_プラグインは自身をドキュメント化する&amp;quot;&amp;gt;ドッグフィーディング : プラグインは自身をドキュメント化する&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_なぜそれが決定的なのかそしてなぜそれが重要なのか&amp;quot;&amp;gt;なぜそれが決定的なのか（そしてなぜそれが重要なのか）&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_パイプライン自身の図&amp;quot;&amp;gt;パイプライン自身の図&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_プロジェクトガバナンスへの統合&amp;quot;&amp;gt;プロジェクトガバナンスへの統合&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_設定_5分間のチェックリスト&amp;quot;&amp;gt;設定 : 5分間のチェックリスト&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_落とし穴と緩和策&amp;quot;&amp;gt;落とし穴と緩和策&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_最終的に得られるもの&amp;quot;&amp;gt;最終的に得られるもの&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_リンク&amp;quot;&amp;gt;リンク&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div id=&amp;quot;preamble&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;読了時間：12 minutes&amp;lt;/div&amp;gt;
&amp;lt;p&amp;gt;あなたのコードベースは大きくなっています。モジュール間の依存関係が増えていきます。アーキテクチャのドキュメントは、書かれる前に古くなってしまいます。あなたのGradleビルドが &amp;lt;em&amp;gt;自動的に&amp;lt;/em&amp;gt; 実際のコード構造から最新の図を生成できたらどうでしょうか？これはまさに、Graphify + PlantUML Gradle プラグイン パイプラインが行うことです：&amp;lt;code&amp;gt;graphify . --no-viz`Knowledge Graph を抽出する&amp;lt;/code&amp;gt;./gradlew generateKnowledgeGraphDiagram`これをPlantUML図に変換します。ゼロLLM、ゼロ手動、100%決定的。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;dlist&amp;quot;&amp;gt;
&amp;lt;dl&amp;gt;
&amp;lt;dt class=&amp;quot;hdlist1&amp;quot;&amp;gt;目次&amp;lt;/dt&amp;gt;
&amp;lt;dd&amp;gt;
&amp;lt;p&amp;gt;[]&amp;lt;/p&amp;gt;
&amp;lt;/dd&amp;gt;
&amp;lt;/dl&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_問題コードに常に遅れを取る図表&amp;quot;&amp;gt;問題：コードに常に遅れを取る図表&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;数千行を超えるプロジェクトはこの症候群に直面します：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;olist arabic&amp;quot;&amp;gt;
&amp;lt;ol class=&amp;quot;arabic&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;プロジェクトの始めにアーキテクチャ図を描きます&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;コードが進化し、依存関係が変わる&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;�図は装飾的な嘘になる&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;誰もそれをアップデートしない、なぜならそれは面倒だから。&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;新参者はそれに基づいて判断し、間違いを犯す&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ol&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
skinparam backgroundColor #FEFEFE
skinparam ActivityBackgroundColor #FDEDEC
skinparam ActivityDiamondBackgroundColor #FFF3CD

start

:Diagramme d&amp;#39;architecture créé\n(manuellement, à la main);

:Le code évolue\n(nouvelles classes, nouvelles dépendances);

:Diagramme obsolète\n(ne reflète plus le code);

if (Qui met à jour ?) then (Personne)
    :Documentation mensongère;
    note right: Les nouveaux développeurs\nse basent dessus... et font des erreurs
else (Quelqu&amp;#39;un)
    :Mise à jour manuelle\n(2-3 heures de travail);
    note right: Déjà obsolète\nà la prochaine PR
endif

stop

@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;質問は、&amp;lt;em&amp;gt;図が必要か？&amp;lt;/em&amp;gt; ではない — みんなそれが必要だと知っている。質問は：&amp;lt;strong&amp;gt;誰がそれらを最新の状態に保っているのですか？&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;答え：誰も。ただし自動の場合を除く。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_解決策決定論的なknowledge_graph_plantumlパイプライン&amp;quot;&amp;gt;解決策：決定論的なKnowledge Graph → PlantUMLパイプライン&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;原理はシンプルです：手で図を描く代わりに、それを&amp;lt;strong&amp;gt;実際のコード構造から生成される&amp;lt;/strong&amp;gt;。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
skinparam backgroundColor #FEFEFE
skinparam componentStyle rectangle

actor Développeur
component &amp;quot;Graphify
(pip install graphifyy)&amp;quot; as Graphify
collections &amp;quot;graphify-out/graph.json
(ナレッジグラフ)&amp;quot; as KGJSON
component &amp;quot;PlantUML Gradle プラグイン\n(generateKnowledgeGraphDiagram)&amp;quot; as Plugin
component &amp;quot;KnowledgeGraphParser&amp;quot; as Parser
component &amp;quot;KnowledgeGraphRenderer&amp;quot; as Renderer
component &amp;quot;PlantumlService\n(検証 + PNGレンダリング)&amp;quot; as PS
collections &amp;quot;diagrams/knowledge-graph/\n(.puml + .png)&amp;quot; as Output

Développeur --&amp;amp;gt; Graphify : graphify . --no-viz
Graphify --&amp;amp;gt; KGJSON : extrait la structure\ndu code source
Développeur --&amp;amp;gt; Plugin : ./gradlew generateKnowledgeGraphDiagram
Plugin --&amp;amp;gt; Parser : parse(graph.json)
Parser --&amp;amp;gt; Plugin : KnowledgeGraph\n(noeuds + arêtes + communautés)
Plugin --&amp;amp;gt; Renderer : render(graph, filters)
Renderer --&amp;amp;gt; Plugin : code PlantUML\ndéterministe
Plugin --&amp;amp;gt; PS : validateSyntax + generateImage
PS --&amp;amp;gt; Output : .puml + .png

note bottom of Plugin
  Pipeline DÉTERMINISTE
  Aucun appel LLM
  Résultat reproductible
end note

@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;2つのコマンド。それだけです。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;# Étape 1 : extraire le Knowledge Graph
graphify . --no-viz

# Étape 2 : générer les diagrammes PlantUML
./gradlew generateKnowledgeGraphDiagram&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;結果？ ファイル`.puml` et &amp;lt;code&amp;gt;.png`中`diagrams/knowledge-graph/&amp;lt;/code&amp;gt;, Git でバージョン管理され, 常にコードと最新の状態を保つ。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_ステップ_1_graphifyをインストールしナレッジグラフを抽出する&amp;quot;&amp;gt;ステップ 1: Graphifyをインストールし、ナレッジグラフを抽出する&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_インストール&amp;quot;&amp;gt;インストール&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;Graphifyはあなたのコードベースを分析し、構造化されたナレッジグラフを構築するPythonツール：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;# Méthode recommandée
uv tool install graphifyy &amp;amp;amp;&amp;amp;amp; graphify install --platform opencode

# Alternative avec pip
pip install graphifyy &amp;amp;amp;&amp;amp;amp; graphify install --platform opencode&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_除外を設定する&amp;quot;&amp;gt;除外を設定する&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;ファイルを作成`.graphifyignore`プロジェクトのルートに置き、ビジネスロジックに属していないファイルを除外します：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-gitignore hljs&amp;quot; data-lang=&amp;quot;gitignore&amp;quot;&amp;gt;# Secrets — JAMAIS dans le graphe
*-context.yml
*.env

# Fichiers générés
build/
.gradle/

# Tests fonctionnels
src/functionalTest/&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_knowledge_graphを抽出する&amp;quot;&amp;gt;Knowledge Graphを�抽出する&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;graphify . --no-viz&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;フラグ`--no-viz`HTMLの生成をスキップします (Gradleパイプラインでは不要です)。 結果はファイルです。`graphify-out/graph.json`含む :&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;結び目&amp;lt;/strong&amp;gt;：クラス、関数、ファイル―そのタイプとコミュニティとともに&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;エッジ&amp;lt;/strong&amp;gt;ノード間の関係 (EXTRACTED はコードから、INFERRED は LLMによって)&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;コミュニティ&amp;lt;/strong&amp;gt;: 自動的にグループ化されたリンクされたノード&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;構造の例`graph.json`&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-json hljs&amp;quot; data-lang=&amp;quot;json&amp;quot;&amp;gt;{
  &amp;quot;nodes&amp;quot;: [
    {&amp;quot;id&amp;quot;: &amp;quot;0&amp;quot;, &amp;quot;label&amp;quot;: &amp;quot;LlmService&amp;quot;, &amp;quot;file_type&amp;quot;: &amp;quot;code&amp;quot;, &amp;quot;community&amp;quot;: 0},
    {&amp;quot;id&amp;quot;: &amp;quot;1&amp;quot;, &amp;quot;label&amp;quot;: &amp;quot;ApiKeyPool&amp;quot;, &amp;quot;file_type&amp;quot;: &amp;quot;code&amp;quot;, &amp;quot;community&amp;quot;: 0},
    {&amp;quot;id&amp;quot;: &amp;quot;2&amp;quot;, &amp;quot;label&amp;quot;: &amp;quot;PlantumlService&amp;quot;, &amp;quot;file_type&amp;quot;: &amp;quot;code&amp;quot;, &amp;quot;community&amp;quot;: 1}
  ],
  &amp;quot;links&amp;quot;: [
    {&amp;quot;source&amp;quot;: &amp;quot;1&amp;quot;, &amp;quot;target&amp;quot;: &amp;quot;0&amp;quot;, &amp;quot;relation&amp;quot;: &amp;quot;uses&amp;quot;, &amp;quot;confidence&amp;quot;: &amp;quot;EXTRACTED&amp;quot;, &amp;quot;weight&amp;quot;: 0.9},
    {&amp;quot;source&amp;quot;: &amp;quot;0&amp;quot;, &amp;quot;target&amp;quot;: &amp;quot;2&amp;quot;, &amp;quot;relation&amp;quot;: &amp;quot;calls&amp;quot;, &amp;quot;confidence&amp;quot;: &amp;quot;INFERRED&amp;quot;, &amp;quot;weight&amp;quot;: 0.7}
  ]
}&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;admonitionblock note&amp;quot;&amp;gt;
&amp;lt;table&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;icon&amp;quot;&amp;gt;
&amp;lt;i class=&amp;quot;fa icon-note&amp;quot; title=&amp;quot;Note&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;
&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;ソースコード (&amp;lt;code&amp;gt;.kt&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;.java&amp;lt;/code&amp;gt;) は tree-sitter によってローカルで分析されます,&amp;lt;strong&amp;gt;�異議なしのLLM&amp;lt;/strong&amp;gt;. ドキュメントファイルのみ (&amp;lt;code&amp;gt;.adoc&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;.md&amp;lt;/code&amp;gt;) LLMを呼び出して意味的抽出を行う必要があります。 それで`--update`Kotlin コードではほぼ瞬時に実行されます。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/table&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_ステップ_2gradleプラグインがknowledge_graphをplantumlに変換します&amp;quot;&amp;gt;ステップ 2：GradleプラグインがKnowledge GraphをPlantUMLに変換します&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_パイプラインアーキテクチャ&amp;quot;&amp;gt;パイプラインアーキテクチャ&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;プラグイン`com.cheroliv.plantuml`タスクを組み込む`generateKnowledgeGraphDiagram`変換する`graph.json`PlantUML図の形で&amp;lt;strong&amp;gt;完全に決定論的&amp;lt;/strong&amp;gt;:&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
skinparam backgroundColor #FEFEFE

participant &amp;quot;Gradle&amp;quot; as G
participant &amp;quot;知識グラフダイアグラム生成タスク&amp;quot; as Task
participant &amp;quot;KnowledgeGraphParser&amp;quot; as Parser
participant &amp;quot;ナレッジグラフレンダラー&amp;quot; as Renderer
participant &amp;quot;Plantumlサービス&amp;quot; as PS

collections &amp;quot;graphify-out/graph.json&amp;quot; as JSON

G -&amp;amp;gt; Task : execute
Task -&amp;amp;gt; JSON : read
Task -&amp;amp;gt; Parser : parse(graph.json)
Parser --&amp;amp;gt; Task : KnowledgeGraph\n(noeuds + arêtes + communautés)
Task -&amp;amp;gt; Renderer : render(graph, filters)
Renderer --&amp;amp;gt; Task : code PlantUML\n(déterministe)
Task -&amp;amp;gt; PS : validateSyntax(plantumlCode)
alt syntaxe valide
    Task -&amp;amp;gt; PS : generateImage → .png
else syntaxe invalide
    Task -&amp;amp;gt; Task : save .puml avec warning
end

@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_内部コンポーネント&amp;quot;&amp;gt;内部コンポーネント&amp;lt;/h3&amp;gt;
&amp;lt;table class=&amp;quot;tableblock frame-all grid-all stretch&amp;quot;&amp;gt;
&amp;lt;colgroup&amp;gt;
&amp;lt;col style=&amp;quot;width: 50%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 50%;&amp;quot;&amp;gt;
&amp;lt;/colgroup&amp;gt;
&amp;lt;thead&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;th class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;コンポーネント&amp;lt;/th&amp;gt;
&amp;lt;th class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;役割&amp;lt;/th&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/thead&amp;gt;
&amp;lt;tbody&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;code&amp;gt;KnowledgeGraphParser&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;解析`graph.json`サポート 3 フォーマット : ネイティブ graphify (&amp;lt;code&amp;gt;nodes&amp;lt;/code&amp;gt;+&amp;lt;code&amp;gt;links&amp;lt;/code&amp;gt;), レガシー (&amp;lt;code&amp;gt;communities&amp;lt;/code&amp;gt;), flat. 数値 ID をラベルに解決します。&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;code&amp;gt;KnowledgeGraphRenderer&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;決定的に変換する一つ`KnowledgeGraph`PlantUML コード。タイプ別にグループ、パッケージにコミュニティ、自動凡例。&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;code&amp;gt;GenerateKnowledgeGraphDiagramTask&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;Gradleタスクは、parse → render → validate → PNGをオーケストレーションします。Gradleプロパティ経由で設定可能。&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;code&amp;gt;kgmodels.kt&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;データモデル：&amp;lt;code&amp;gt;KnowledgeGraph&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;KnowledgeGraphNode&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;KnowledgeGraphEdge&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;KnowledgeGraphCommunity&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;EdgeType&amp;lt;/code&amp;gt;。&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;code&amp;gt;PlantumlService&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;構文検証 + PNGレンダリング（プラグインのすべてのタスクで再利用）&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/tbody&amp;gt;
&amp;lt;/table&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_レンダリングルール&amp;quot;&amp;gt;レンダリングルール&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;レンダラーは決定論的な視覚的慣習を適用します：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;table class=&amp;quot;tableblock frame-all grid-all stretch&amp;quot;&amp;gt;
&amp;lt;colgroup&amp;gt;
&amp;lt;col style=&amp;quot;width: 33.3333%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 33.3333%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 33.3334%;&amp;quot;&amp;gt;
&amp;lt;/colgroup&amp;gt;
&amp;lt;thead&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;th class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;エッジのタイプ&amp;lt;/th&amp;gt;
&amp;lt;th class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;PlantUML記法&amp;lt;/th&amp;gt;
&amp;lt;th class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;意味&amp;lt;/th&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/thead&amp;gt;
&amp;lt;tbody&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;�抽出された&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;code&amp;gt;-&amp;amp;#8594;&amp;lt;/code&amp;gt;(実線, 黒)&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;ソースコードから抽出された関係 (確実性)&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;推論された&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;code&amp;gt;..&amp;amp;gt;&amp;lt;/code&amp;gt;(点線)&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;LLMによって推論された関係 （信頼スコア）&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;あいまいな&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;code&amp;gt;--x&amp;lt;/code&amp;gt;(赤い点線)&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;�曖昧な関係 (確認が必要)&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/tbody&amp;gt;
&amp;lt;/table&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;コミュニティは、自動色パレットを持つ PlantUML パッケージとしてレンダリングされます。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_ステップ3日常での使用&amp;quot;&amp;gt;ステップ3：日常での使用&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_完全図&amp;quot;&amp;gt;完全図&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;# Générer le diagramme du Knowledge Graph complet
./gradlew generateKnowledgeGraphDiagram&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;出力：&amp;lt;code&amp;gt;diagrams/knowledge-graph/knowledge-graph-full.puml&amp;lt;/code&amp;gt;（空）&amp;lt;code&amp;gt;.png&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_コミュニティで絞り込む&amp;quot;&amp;gt;コミュニティで絞り込む&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;# Une seule communauté
./gradlew generateKnowledgeGraphDiagram \
  -Pplantuml.kg.community=community_0

# Limiter le nombre de noeuds (lisibilité)
./gradlew generateKnowledgeGraphDiagram \
  -Pplantuml.kg.community=community_0 \
  -Pplantuml.kg.maxNodes=15&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_エッジの種類でフィルタリング&amp;quot;&amp;gt;エッジの種類でフィルタリング&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;# Uniquement les relations certaines (EXTRACTED)
./gradlew generateKnowledgeGraphDiagram \
  -Pplantuml.kg.edgeTypes=EXTRACTED

# Relations certaines + inférées
./gradlew generateKnowledgeGraphDiagram \
  -Pplantuml.kg.edgeTypes=EXTRACTED,INFERRED&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_ノードの種類と信頼度でフィルター&amp;quot;&amp;gt;ノードの種類と信頼度でフィルター&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;# Uniquement les classes de code
./gradlew generateKnowledgeGraphDiagram \
  -Pplantuml.kg.nodeTypes=code

# Seuil de confiance minimum (pour les INFERRED)
./gradlew generateKnowledgeGraphDiagram \
  -Pplantuml.kg.minConfidence=0.7&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_カスタム出力ディレクトリ&amp;quot;&amp;gt;カスタム出力ディレクトリ&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;./gradlew generateKnowledgeGraphDiagram \
  -Pplantuml.kg.outputDir=docs/architecture&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_プロパティの完全な参照&amp;quot;&amp;gt;プロパティの完全な参照&amp;lt;/h3&amp;gt;
&amp;lt;table class=&amp;quot;tableblock frame-all grid-all stretch&amp;quot;&amp;gt;
&amp;lt;colgroup&amp;gt;
&amp;lt;col style=&amp;quot;width: 33.3333%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 33.3333%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 33.3334%;&amp;quot;&amp;gt;
&amp;lt;/colgroup&amp;gt;
&amp;lt;thead&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;th class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;所有権&amp;lt;/th&amp;gt;
&amp;lt;th class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;デフォルト&amp;lt;/th&amp;gt;
&amp;lt;th class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;説明&amp;lt;/th&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/thead&amp;gt;
&amp;lt;tbody&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;code&amp;gt;plantuml.kg.community&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;(すべて)&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;名前でコミュニティをフィルタリング（部分一致）&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;code&amp;gt;plantuml.kg.edgeTypes&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;em&amp;gt;(皆)&amp;lt;/em&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;カンマで区切られたエッジの種類：&amp;lt;code&amp;gt;EXTRACTED&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;INFERRED&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;AMBIGUOUS&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;code&amp;gt;plantuml.kg.minConfidence&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;code&amp;gt;0.0&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;エッジの最小信頼しきい値&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;code&amp;gt;plantuml.kg.maxNodes&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;(無制限)&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;表示する最大ノード数&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;code&amp;gt;plantuml.kg.nodeTypes&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;(すべて)&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;ノードの種類、カンマで区切られた（例`class`, &amp;lt;code&amp;gt;code&amp;lt;/code&amp;gt;)&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;code&amp;gt;plantuml.kg.outputDir&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;code&amp;gt;diagrams/knowledge-graph&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;ファイルの出力ディレクトリ`.puml` et &amp;lt;code&amp;gt;.png&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/tbody&amp;gt;
&amp;lt;/table&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_gradle_ワークフローにおける完全なパイプライン&amp;quot;&amp;gt;Gradle ワークフローにおける完全なパイプライン&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_ワークフローのタイプ&amp;quot;&amp;gt;ワークフローのタイプ&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
skinparam backgroundColor #FEFEFE
skinparam ActivityBackgroundColor #E8F4FD
skinparam ActivityDiamondBackgroundColor #FFF3CD
skinparam ActivityBorderColor #2C3E50

start

partition &amp;quot;抽出&amp;quot; {
    :graphify . --no-viz;
    note right: Analyse le code source\ntree-sitter (local, pas de LLM)

    :graphify-out/graph.json;
    note right: Noeuds + arêtes\n+ communautés
}

partition &amp;quot;世代&amp;quot; {
    :./gradlew generateKnowledgeGraphDiagram;
    note right: Pipeline déterministe\nparse → render → validate → PNG

    if (Filtres actifs ?) then (Oui)
        :Appliquer filtres\n(community, edgeTypes,\nmaxNodes, nodeTypes);
    else (Non)
        :Diagramme complet;
    endif

    :diagrams/knowledge-graph/\nknowledge-graph-full.puml\nknowledge-graph-full.png;
}

partition &amp;quot;統合&amp;quot; {
    :git add diagrams/knowledge-graph/;
    :git commit;
    note right: Diagrammes versionnés\ntoujours à jour avec le code
}

stop

@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_開発サイクルへの統合&amp;quot;&amp;gt;開発サイクルへの統合&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;パイプラインは開発の重要な段階に自然に統合されます：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
skinparam backgroundColor #FEFEFE

state &amp;quot;開発&amp;quot; as dev
state &amp;quot;�抽出
graphify . --no-viz&amp;quot; as extract
state &amp;quot;生成\n./gradlew generateKnowledgeGraphDiagram&amp;quot; as generate
state &amp;quot;コミット
バージョン管理されたダイアグラム&amp;quot; as commit

[*] --&amp;amp;gt; dev
dev --&amp;amp;gt; extract : Code modifié
extract --&amp;amp;gt; generate : graph.json à jour
generate --&amp;amp;gt; commit : .puml + .png générés
commit --&amp;amp;gt; dev : Diagrammes dans le repo

note right of extract
  Quasi instantané sur du code Kotlin
  (tree-sitter, pas de LLM)
end note

note right of generate
  Déterministe
  Pas de LLM
  Résultat reproductible
end note

@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_インクリメンタルアップデート&amp;quot;&amp;gt;インクリメンタルアップデート&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;コードが変更されたとき、ゼロからグラフ全体を再構築するわけではありません：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;# Mise à jour incrémentale (fichiers modifiés uniquement)
graphify . --update

# Puis régénérer les diagrammes
./gradlew generateKnowledgeGraphDiagram&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;admonitionblock note&amp;quot;&amp;gt;
&amp;lt;table&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;icon&amp;quot;&amp;gt;
&amp;lt;i class=&amp;quot;fa icon-note&amp;quot; title=&amp;quot;Note&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;
&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;code&amp;gt;--update`再抽出のみ 変更されたファイル (SHA256で検出された`graphify-out/cache/&amp;lt;/code&amp;gt;) Kotlin のコードでは、tree-sitter がローカルで動作し LLM を呼び出さないため、ほぼ瞬時に動作します。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/table&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_ドッグフィーディング_プラグインは自身をドキュメント化する&amp;quot;&amp;gt;ドッグフィーディング : プラグインは自身をドキュメント化する&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;PlantUML プラグインは、プロンプトをダイアグラムに変換するために存在します。また、自分の &amp;lt;em&amp;gt;propre&amp;lt;/em&amp;gt; コードベースの Knowledge Graph もドキュメント用ダイアグラムに変換できます。これは &amp;lt;em&amp;gt;dogfooding&amp;lt;/em&amp;gt; です：プラグインは自分のサービスを利用します。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
skinparam backgroundColor #FEFEFE
skinparam componentStyle rectangle

package &amp;quot;標準パイプライン
(ユーザー → ダイアグラム)&amp;quot; as normal {
    [Fichier .prompt] as prompt
    [LlmService\n+ ApiKeyPool] as llm1
    [ProcessPlantumlPromptsTask] as task1
    [Diagramme PNG] as out1

    prompt --&amp;amp;gt; task1
    task1 --&amp;amp;gt; llm1
    llm1 --&amp;amp;gt; out1
}

package &amp;quot;Pipeline Knowledge Graph\n(決定論的、LLMを使用しない)&amp;quot; as kg {
    [graphify-out/graph.json] as kgjson
    [KnowledgeGraphParser] as parser
    [KnowledgeGraphRenderer] as renderer
    [PlantumlService] as ps
    [Diagramme PNG\n(documentation du plugin)] as out2

    kgjson --&amp;amp;gt; parser
    parser --&amp;amp;gt; renderer
    renderer --&amp;amp;gt; ps
    ps --&amp;amp;gt; out2
}

package &amp;quot;パイプライン ドッグフーディング
(LLM → プラグインのドキュメント)&amp;quot; as dogfood {
    [GraphifyPromptAdapter] as gpa
    [Fichiers .prompt\nauto-générés] as auto_prompt
    [LlmService\n+ ApiKeyPool] as llm2
    [ProcessPlantumlPromptsTask] as task2
    [Diagramme PNG\n(documentation LLM)] as out3

    kgjson --&amp;amp;gt; gpa
    gpa --&amp;amp;gt; auto_prompt
    auto_prompt --&amp;amp;gt; task2
    task2 --&amp;amp;gt; llm2
    llm2 --&amp;amp;gt; out3
}

note &amp;quot;同じ LlmService、同じ ApiKeyPool、
同じ PlantumlService
— 複製ゼロ&amp;quot; as N

@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;関連付けられた Gradle タスク :&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;table class=&amp;quot;tableblock frame-all grid-all stretch&amp;quot;&amp;gt;
&amp;lt;colgroup&amp;gt;
&amp;lt;col style=&amp;quot;width: 33.3333%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 33.3333%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 33.3334%;&amp;quot;&amp;gt;
&amp;lt;/colgroup&amp;gt;
&amp;lt;thead&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;th class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;タスク&amp;lt;/th&amp;gt;
&amp;lt;th class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;LLM ?&amp;lt;/th&amp;gt;
&amp;lt;th class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;説明&amp;lt;/th&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/thead&amp;gt;
&amp;lt;tbody&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;code&amp;gt;generateKnowledgeGraphDiagram&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;いいえ&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;変換`graph.json`PlantUML (決定的)で&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;code&amp;gt;generateDiagramDocs&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;はい&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;生成する`.prompt`グラフから、LLM（dogfooding）を使って処理しています。&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/tbody&amp;gt;
&amp;lt;/table&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;# Documentation déterministe (rapide, pas de LLM)
./gradlew generateKnowledgeGraphDiagram

# Documentation LLM (plus riche, consomme des tokens)
./gradlew generateDiagramDocs&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_なぜそれが決定的なのかそしてなぜそれが重要なのか&amp;quot;&amp;gt;なぜそれが決定的なのか（そしてなぜそれが重要なのか）&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;パイプラインの重要なポイント`generateKnowledgeGraphDiagram` : &amp;lt;strong&amp;gt;彼はどのLLMも呼び出さない&amp;lt;/strong&amp;gt;. 変換`graph.json`→ PlantUML は純粋関数です。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
skinparam backgroundColor #FEFEFE
skinparam componentStyle rectangle

rectangle &amp;quot;決定的パイプライン
(generateKnowledgeGraphDiagram)&amp;quot; as det {
    [graph.json] as json
    [KnowledgeGraphParser] as parser
    [KnowledgeGraphRenderer] as renderer
    [PlantUML code] as puml

    json --&amp;amp;gt; parser : parse
    parser --&amp;amp;gt; renderer : KnowledgeGraph
    renderer --&amp;amp;gt; puml : render (fonction pure)
}

rectangle &amp;quot;パイプライン LLM
(processPlantumlPrompts)&amp;quot; as llm {
    [.prompt] as prompt
    [LlmService] as llmSvc
    [ChatModel] as model
    [PlantUML code] as puml2

    prompt --&amp;amp;gt; llmSvc
    llmSvc --&amp;amp;gt; model : API call
    model --&amp;amp;gt; puml2 : réponse non-déterministe
}

note bottom of det
  Même entrée → même sortie
  Pas de latence réseau
  Pas de coût en tokens
  Reproductible en CI
end note

note bottom of llm
  Même entrée → sortie variable
  Latence réseau (1-5s)
  Coût en tokens
  Nécessite une clave API
end note

@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;具体的な利点：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;table class=&amp;quot;tableblock frame-all grid-all stretch&amp;quot;&amp;gt;
&amp;lt;colgroup&amp;gt;
&amp;lt;col style=&amp;quot;width: 50%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 50%;&amp;quot;&amp;gt;
&amp;lt;/colgroup&amp;gt;
&amp;lt;thead&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;th class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;利点&amp;lt;/th&amp;gt;
&amp;lt;th class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;インパクト&amp;lt;/th&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/thead&amp;gt;
&amp;lt;tbody&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;再現性&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;同じ`graph.json`→ 同じ図。正確です。毎回。&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;ゼロコスト&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;LLMの呼び出しなし = トークンなし = API請求なし&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;ゼロレイテンシー&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;Parse + render は~100msかかり、1〜5秒ではありません。&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;CI対応&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;APIキーは必要ありません。変動するLLMの応答によるフレークなテストは発生しません。&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;バージョン可能&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;Le &amp;lt;code&amp;gt;.puml`テキストは生成される。私たちそれをできる`diff&amp;lt;/code&amp;gt;, PRのレビュアー, Gitでバージョン管理する。&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/tbody&amp;gt;
&amp;lt;/table&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_パイプライン自身の図&amp;quot;&amp;gt;パイプライン自身の図&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;ループを閉じるために、プラグインによって生成されるパイプラインの図を以下に示します：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
skinparam backgroundColor #FEFEFE

participant &amp;quot;開発者&amp;quot; as Dev
participant &amp;quot;グラドル&amp;quot; as G
participant &amp;quot;知識グラフ図を生成するタスク&amp;quot; as Task
participant &amp;quot;KnowledgeGraphParser&amp;quot; as Parser
participant &amp;quot;ナレッジグラフレンダラー&amp;quot; as Renderer
participant &amp;quot;PlantUMLサービス&amp;quot; as PS
collections &amp;quot;graphify-out/graph.json&amp;quot; as JSON
collections &amp;quot;diagrams/knowledge-graph/&amp;quot; as Out

Dev -&amp;amp;gt; G : ./gradlew generateKnowledgeGraphDiagram
G -&amp;amp;gt; Task : execute
Task -&amp;amp;gt; JSON : read
Task -&amp;amp;gt; Parser : parse(graph.json)
Parser --&amp;amp;gt; Task : KnowledgeGraph

alt filtres actifs
    Task -&amp;amp;gt; Task : appliquer filtres\n(community, edgeTypes, maxNodes…)
end

Task -&amp;amp;gt; Renderer : render(graph, filters)
Renderer --&amp;amp;gt; Task : code PlantUML

Task -&amp;amp;gt; PS : validateSyntax()
alt valide
    Task -&amp;amp;gt; PS : generateImage()
    PS --&amp;amp;gt; Out : .puml + .png
else invalide
    Task -&amp;amp;gt; Out : .puml (avec warning)
end

@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_プロジェクトガバナンスへの統合&amp;quot;&amp;gt;プロジェクトガバナンスへの統合&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;私たちのプロジェクトでは、このパイプラインはAIエージェントのためのEAGER/LAZYコンテキスト管理戦略に組み込まれます。ナレッジグラフは、手動のアーキテクチャドキュメントに代わり、構造化され、クエリ可能で、自動的に更新されるグラフを提供します。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
skinparam backgroundColor #FEFEFE
skinparam componentStyle rectangle

package &amp;quot;EAGER
(常に充電されている)&amp;quot; as eager {
    [PROMPT_REPRISE.adoc\n(contexte session)] as pr
    [INDEX.adoc\n(vue d&amp;#39;ensemble)] as idx
    [GRAPH_REPORT.adoc\n(~50 lignes)] as gr
}

package &amp;quot;LAZY — 戦略
(要請による)&amp;quot; as lazy_strat {
    [Méthodologies] as meth
    [Archives sessions] as sessions
}

package &amp;quot;LAZY — Graphify
(ターゲットクエリ)&amp;quot; as lazy_graph {
    [graph.json] as gj
    [Queries\n(query/path/explain)] as queries
}

package &amp;quot;Pipeline PlantUML
(自動生成された)&amp;quot; as puml {
    [generateKnowledgeGraphDiagram] as kgTask
    [generateDiagramDocs] as ddTask
    [Diagrammes PNG] as diagrams
}

Agent --&amp;amp;gt; eager : Lit en début de session
Agent ..&amp;amp;gt; lazy_strat : Charge si type détecté
Agent ..&amp;amp;gt; lazy_graph : Query si besoin structurel
kgTask --&amp;amp;gt; diagrams : Déterministe
ddTask --&amp;amp;gt; diagrams : Via LLM

note right of gr
  Condensé du Knowledge Graph
  God nodes + communautés
  Remplace ECOSYSTEM_OVERVIEW
  (225 lignes → 50 lignes)
end note

@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;二つのシステムの結びつきは補完的である:&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;戦略は「いつ」と「どのように」を管理する&amp;lt;/strong&amp;gt;— ガバナンス, ワークフロー, アーカイブ&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;GraphifyはQUOIとOÙを管理します&amp;lt;/strong&amp;gt;コード構造, 関係, ターゲット絞り込みクエリ&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;em&amp;gt;&amp;lt;em&amp;gt;_ セッション戦略はを管理します&amp;lt;strong&amp;gt;いつ&amp;lt;/strong&amp;gt; et le &amp;lt;strong&amp;gt;どう&amp;lt;/strong&amp;gt;(ガバナンス, ワークフロー, しきい値), Graphifyは管理します&amp;lt;strong&amp;gt;何？&amp;lt;/strong&amp;gt; et le &amp;lt;strong&amp;gt;どこ&amp;lt;/strong&amp;gt;(コードの構造、関係、ターゲットクエリ). PlantUMLパイプラインは管理します&amp;lt;strong&amp;gt;何で&amp;lt;/strong&amp;gt;(決定論的でバージョン管理され、常に最新の図) &amp;lt;/em&amp;gt;_&amp;lt;/em&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_設定_5分間のチェックリスト&amp;quot;&amp;gt;設定 : 5分間のチェックリスト&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;table class=&amp;quot;tableblock frame-all grid-all stretch&amp;quot;&amp;gt;
&amp;lt;colgroup&amp;gt;
&amp;lt;col style=&amp;quot;width: 33.3333%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 33.3333%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 33.3334%;&amp;quot;&amp;gt;
&amp;lt;/colgroup&amp;gt;
&amp;lt;thead&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;th class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;#&amp;lt;/th&amp;gt;
&amp;lt;th class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;ステップ&amp;lt;/th&amp;gt;
&amp;lt;th class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;注文&amp;lt;/th&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/thead&amp;gt;
&amp;lt;tbody&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;1&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;Graphifyをインストール&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;code&amp;gt;uv tool install graphifyy&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;2&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;除外を設定&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;作成する`.graphifyignore`&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;3&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;Knowledge Graphを抽出する&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;code&amp;gt;graphify . --no-viz&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;4&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;図を生成する&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;code&amp;gt;./gradlew generateKnowledgeGraphDiagram&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;5&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;結果をコミットする&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;code&amp;gt;git add diagrams/knowledge-graph/&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/tbody&amp;gt;
&amp;lt;/table&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;# Script complet en 5 commandes
uv tool install graphifyy
cat &amp;amp;gt; .graphifyignore &amp;amp;lt;&amp;amp;lt; &amp;#39;EOF&amp;#39;
*-context.yml
*.env
build/
.gradle/
EOF
graphify . --no-viz
./gradlew generateKnowledgeGraphDiagram
git add graphify-out/GRAPH_REPORT.adoc graphify-out/graph.json diagrams/knowledge-graph/&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_落とし穴と緩和策&amp;quot;&amp;gt;落とし穴と緩和策&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;table class=&amp;quot;tableblock frame-all grid-all stretch&amp;quot;&amp;gt;
&amp;lt;colgroup&amp;gt;
&amp;lt;col style=&amp;quot;width: 33.3333%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 33.3333%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 33.3334%;&amp;quot;&amp;gt;
&amp;lt;/colgroup&amp;gt;
&amp;lt;thead&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;th class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;�罠&amp;lt;/th&amp;gt;
&amp;lt;th class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;説明&amp;lt;/th&amp;gt;
&amp;lt;th class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;緩和&amp;lt;/th&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/thead&amp;gt;
&amp;lt;tbody&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;グラフが濃すぎる&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;大きなプロジェクトは、数百の読み取り不能なノードを生成します&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;使用する`-Pplantuml.kg.maxNodes=30`そしてコミュニティでフィルタリング&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;除外が広すぎる&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;多すぎるファイルが`.graphifyignore`グラフの値を減少させる&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;まずは credentials と build のみを除外して始める&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;�矢印の方向&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;INFERREDエッジはあいまいな方向を持つ可能性がある&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;フィルターで`-Pplantuml.kg.edgeTypes=EXTRACTED`特定の関係に対してのみ&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;旧式のグラフ&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;コードは変わるが、グラフは再構築されない&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;使う`graphify . --update`定期的にまたはgitフック`graphify hook install`&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;更新されたコスト&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;インクリメンタルアップデートはほぼ無料です (tree-sitter local)&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;ドキュメントだけ(&amp;lt;code&amp;gt;.adoc&amp;lt;/code&amp;gt;) LLMトークンを消費する&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/tbody&amp;gt;
&amp;lt;/table&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_最終的に得られるもの&amp;quot;&amp;gt;最終的に得られるもの&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
skinparam backgroundColor #FEFEFE

rectangle &amp;quot;前に&amp;quot; as avant {
    card &amp;quot;手描きの図
常に時代遅れ
誰も更新しない&amp;quot; as av1 #FDEDEC
}

rectangle &amp;quot;後で&amp;quot; as apres {
    card &amp;quot;自動生成されたダイアグラム
コードと常に最新状態
Gitでバージョン管理
決定論的かつ再現可能&amp;quot; as ap1 #E8F8E8
}

avant --&amp;amp;gt; apres : graphify . --no-viz\n+ ./gradlew generateKnowledgeGraphDiagram

@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;具体的な利益：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;table class=&amp;quot;tableblock frame-all grid-all stretch&amp;quot;&amp;gt;
&amp;lt;colgroup&amp;gt;
&amp;lt;col style=&amp;quot;width: 50%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 50%;&amp;quot;&amp;gt;
&amp;lt;/colgroup&amp;gt;
&amp;lt;thead&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;th class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;利益&amp;lt;/th&amp;gt;
&amp;lt;th class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;詳細&amp;lt;/th&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/thead&amp;gt;
&amp;lt;tbody&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;常に最新のドキュメンテーション&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;�図は現在のコードを反映しており、手動のスナップショットではありません。&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;メンテナンスの手間ゼロ&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;�図はビルドごとに再生成されます&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;技術的負債の削減&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;図を手動で維持する必要はありません&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;新しいもののためのビジュアルコンテキスト&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;新しい開発者は図を見てアーキテクチャを理解する&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;ファインチューニングの可能性&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;ペア (サブグラフ → ダイアグラム) は AI のトレーニングの例です&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;自動検証&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;`PlantumlService.validateSyntax()`生成された各図を確認する&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;迅速なオンボーディング&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;5つのダイアグラム = アーキテクチャの完全なビュー&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/tbody&amp;gt;
&amp;lt;/table&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;(Empty output) なぜがある者は、いかなる「どうすればいいか」にも耐えることができる。 &amp;lt;em&amp;gt;__&amp;lt;/em&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;Le &amp;lt;em&amp;gt;pourquoi&amp;lt;/em&amp;gt; : 図は常に最新状態。Le &amp;lt;em&amp;gt;comment&amp;lt;/em&amp;gt; : Gradle パイプライン内の 2 つのコマンド。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_リンク&amp;quot;&amp;gt;リンク&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;https://github.com/nicholasgasior/graphify&amp;quot;&amp;gt;GitHubでGraphify&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;https://github.com/cheroliv/plantuml-gradle&amp;quot;&amp;gt;PlantUML Gradle プラグイン&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;/blog/2026/0104_fg_command_super_tips_post.html&amp;quot;&amp;gt;fg コマンドのスーパー テクニック&amp;lt;/a&amp;gt;— ターミナルワークフローに関する前の記事&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;</description>
        </item><item>
            <title>GraphifyをGradleワークフローに統合：ナレッジグラフからPlantUML図までを1コマンドで</title>
            <link >https://cheroliv.com/blog/2026/0105_integrer_graphify_workflow_gradle_post.html</link>
            <pubDate>Sun, 19 Apr 2026 00:00:00 +0000</pubDate>
            <guid isPermaLink="false">blog/2026/0105_integrer_graphify_workflow_gradle_post.html</guid>
            <description>&amp;lt;div id=&amp;quot;toc&amp;quot; class=&amp;quot;toc&amp;quot;&amp;gt;
&amp;lt;div id=&amp;quot;toctitle&amp;quot;&amp;gt;Table des matières&amp;lt;/div&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel1&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_問題図は常にコードに遅れている&amp;quot;&amp;gt;問題：図は常にコードに遅れている&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_解決策決定論的パイプライン_knowledge_graph_plantuml&amp;quot;&amp;gt;解決策：決定論的パイプライン Knowledge Graph → PlantUML&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_ステップ1_graphifyをインストールしknowledge_graphを抽出する&amp;quot;&amp;gt;ステップ1 : Graphifyをインストールし、Knowledge Graphを抽出する&amp;lt;/a&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel2&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_インストール&amp;quot;&amp;gt;インストール&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_除外を設定する&amp;quot;&amp;gt;除外を設定する&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_ナレッジグラフを抽出&amp;quot;&amp;gt;ナレッジグラフを抽出&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_ステップ_2_gradle_プラグインは_knowledge_graph_を_plantuml_に変換します&amp;quot;&amp;gt;ステップ 2 : Gradle プラグインは Knowledge Graph を PlantUML に変換します&amp;lt;/a&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel2&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_パイプラインアーキテクチャ&amp;quot;&amp;gt;パイプラインアーキテクチャ&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_内部コンポーネント&amp;quot;&amp;gt;内部コンポーネント&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_レンダリングルール&amp;quot;&amp;gt;レンダリングルール&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_ステップ_3_日常での使用&amp;quot;&amp;gt;ステップ 3: 日常での使用&amp;lt;/a&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel2&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_完全な図&amp;quot;&amp;gt;完全な図&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_コミュニティでフィルタリング&amp;quot;&amp;gt;コミュニティでフィルタリング&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_エッジの種類でフィルタリング&amp;quot;&amp;gt;エッジの種類でフィルタリング&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_ノードのタイプと信頼度でフィルタリング&amp;quot;&amp;gt;ノードのタイプと信頼度でフィルタリング&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_カスタマイズされた出力ディレクトリ&amp;quot;&amp;gt;カスタマイズされた出力ディレクトリ&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_プロパティの完全なリファレンス&amp;quot;&amp;gt;プロパティの完全なリファレンス&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_gradle_ワークフローにおける完全なパイプライン&amp;quot;&amp;gt;Gradle ワークフローにおける完全なパイプライン&amp;lt;/a&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel2&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_ワークフローの種類&amp;quot;&amp;gt;ワークフローの種類&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_開発サイクルへの統合&amp;quot;&amp;gt;開発サイクルへの統合&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_インクリメンタルアップデート&amp;quot;&amp;gt;インクリメンタルアップデート&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_ドッグフーディングプラグインは自分自身をドキュメント化する&amp;quot;&amp;gt;ドッグフーディング：プラグインは自分自身をドキュメント化する&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_なぜそれが決定的なのか_そしてそれが重要である理由&amp;quot;&amp;gt;なぜそれが決定的なのか (そしてそれが重要である理由)&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_パイプライン自体の図&amp;quot;&amp;gt;パイプライン自体の図&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_プロジェクトガバナンスへの統合&amp;quot;&amp;gt;プロジェクトガバナンスへの統合&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_準備_5分のチェックリスト&amp;quot;&amp;gt;準備 : 5分のチェックリスト&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_罠と軽減策&amp;quot;&amp;gt;罠と軽減策&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_最終的に得られるもの&amp;quot;&amp;gt;最終的に得られるもの&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_リンク&amp;quot;&amp;gt;リンク&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div id=&amp;quot;preamble&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;読了時間 : 12 minutes&amp;lt;/div&amp;gt;
&amp;lt;p&amp;gt;コードベースは大きくなっています。モジュール間の依存関係が増え続けています。アーキテクチャのドキュメントは、書かれる前に古くなります。あなたのGradleビルドが、実際のコード構造から最新の図を &amp;lt;em&amp;gt;自動的に&amp;lt;/em&amp;gt; 生成できたらどうでしょう？これは、Graphify + PlantUML Gradle Plugin パイプラインがまさに行うことです：&amp;lt;code&amp;gt;graphify . --no-viz`Knowledge Graphを抽出する,&amp;lt;/code&amp;gt;./gradlew generateKnowledgeGraphDiagram`これはPlantUMLのダイアグラムに変換します。LLMゼロ、マニュアルゼロ、100%決定論的。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;dlist&amp;quot;&amp;gt;
&amp;lt;dl&amp;gt;
&amp;lt;dt class=&amp;quot;hdlist1&amp;quot;&amp;gt;強迫性障害&amp;lt;/dt&amp;gt;
&amp;lt;dd&amp;gt;
&amp;lt;p&amp;gt;(empty)&amp;lt;/p&amp;gt;
&amp;lt;/dd&amp;gt;
&amp;lt;/dl&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_問題図は常にコードに遅れている&amp;quot;&amp;gt;問題：図は常にコードに遅れている&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;数千行を超えるプロジェクトはこの症候群を経験する：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;olist arabic&amp;quot;&amp;gt;
&amp;lt;ol class=&amp;quot;arabic&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;プロジェクトの初期にアーキテクチャ図を描きます&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;コードは進化し、依存関係は変わる&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;�図は装飾的な嘘になる&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;誰もそれを更新しないのは、面倒だから&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;新参者はそれに基づいて行動し、間違いを犯す&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ol&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
skinparam backgroundColor #FEFEFE
skinparam ActivityBackgroundColor #FDEDEC
skinparam ActivityDiamondBackgroundColor #FFF3CD

start

:Diagramme d&amp;#39;architecture créé\n(manuellement, à la main);

:Le code évolue\n(nouvelles classes, nouvelles dépendances);

:Diagramme obsolète\n(ne reflète plus le code);

if (Qui met à jour ?) then (Personne)
    :Documentation mensongère;
    note right: Les nouveaux développeurs\nse basent dessus... et font des erreurs
else (Quelqu&amp;#39;un)
    :Mise à jour manuelle\n(2-3 heures de travail);
    note right: Déjà obsolète\nà la prochaine PR
endif

stop

@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;問題は &amp;lt;em&amp;gt;図が必要か？&amp;lt;/em&amp;gt; — みんなが知っている通り、はいです。問題は：&amp;lt;strong&amp;gt;誰がそれらを最新に保っていますか？&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;答え：だれもいない。ただし、自動の場合は除きます。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_解決策決定論的パイプライン_knowledge_graph_plantuml&amp;quot;&amp;gt;解決策：決定論的パイプライン Knowledge Graph → PlantUML&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;原理はシンプルです：手で図を描く代わりに、それらを&amp;lt;strong&amp;gt;実際のコード構造から生成されます&amp;lt;/strong&amp;gt;。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
skinparam backgroundColor #FEFEFE
skinparam componentStyle rectangle

actor Développeur
component &amp;quot;Graphify\n(pip install graphifyy)&amp;quot; as Graphify
collections &amp;quot;graphify-out/graph.json
(ナレッジグラフ)&amp;quot; as KGJSON
component &amp;quot;PlantUML Gradleプラグイン\n(generateKnowledgeGraphDiagram)&amp;quot; as Plugin
component &amp;quot;KnowledgeGraphParser&amp;quot; as Parser
component &amp;quot;ナレッジグラフレンダラー&amp;quot; as Renderer
component &amp;quot;PlantumlService
(検証 + PNGレンダリング)&amp;quot; as PS
collections &amp;quot;diagrams/knowledge-graph/\n(.puml + .png)&amp;quot; as Output

Développeur --&amp;amp;gt; Graphify : graphify . --no-viz
Graphify --&amp;amp;gt; KGJSON : extrait la structure\ndu code source
Développeur --&amp;amp;gt; Plugin : ./gradlew generateKnowledgeGraphDiagram
Plugin --&amp;amp;gt; Parser : parse(graph.json)
Parser --&amp;amp;gt; Plugin : KnowledgeGraph\n(noeuds + arêtes + communautés)
Plugin --&amp;amp;gt; Renderer : render(graph, filters)
Renderer --&amp;amp;gt; Plugin : code PlantUML\ndéterministe
Plugin --&amp;amp;gt; PS : validateSyntax + generateImage
PS --&amp;amp;gt; Output : .puml + .png

note bottom of Plugin
  Pipeline DÉTERMINISTE
  Aucun appel LLM
  Résultat reproductible
end note

@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;2つのコマンド。それだけです。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;# Étape 1 : extraire le Knowledge Graph
graphify . --no-viz

# Étape 2 : générer les diagrammes PlantUML
./gradlew generateKnowledgeGraphDiagram&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;結果は？ ファイル`.puml` et &amp;lt;code&amp;gt;.png`中`diagrams/knowledge-graph/&amp;lt;/code&amp;gt;, Git でバージョン管理されている, 常にコードに対して最新の状態を保っています。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_ステップ1_graphifyをインストールしknowledge_graphを抽出する&amp;quot;&amp;gt;ステップ1 : Graphifyをインストールし、Knowledge Graphを抽出する&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_インストール&amp;quot;&amp;gt;インストール&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;Graphify は、コードベースを分析し、構造化されたナレッジグラフを構築する Python ツールです：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;# Méthode recommandée
uv tool install graphifyy &amp;amp;amp;&amp;amp;amp; graphify install --platform opencode

# Alternative avec pip
pip install graphifyy &amp;amp;amp;&amp;amp;amp; graphify install --platform opencode&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_除外を設定する&amp;quot;&amp;gt;除外を設定する&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;ファイルを作成`.graphifyignore`プロジェクトのルートでビジネスロジックに属しないファイルを除外する：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-gitignore hljs&amp;quot; data-lang=&amp;quot;gitignore&amp;quot;&amp;gt;# Secrets — JAMAIS dans le graphe
*-context.yml
*.env

# Fichiers générés
build/
.gradle/

# Tests fonctionnels
src/functionalTest/&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_ナレッジグラフを抽出&amp;quot;&amp;gt;ナレッジグラフを抽出&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;graphify . --no-viz&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;フラグ`--no-viz`HTML生成をスキップします（Gradleパイプラインでは不要です）。結果はファイルです。`graphify-out/graph.json`含む :&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;ノード&amp;lt;/strong&amp;gt;クラス、関数、ファイル — それらのタイプとコミュニティ&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;エッジ&amp;lt;/strong&amp;gt;: ノード間の関係 (コードから抽出, LLMによって推測)&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;コミュニティ&amp;lt;/strong&amp;gt;: 自動的な関連ノードのグループ化&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;構造の例`graph.json`&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-json hljs&amp;quot; data-lang=&amp;quot;json&amp;quot;&amp;gt;{
  &amp;quot;nodes&amp;quot;: [
    {&amp;quot;id&amp;quot;: &amp;quot;0&amp;quot;, &amp;quot;label&amp;quot;: &amp;quot;LlmService&amp;quot;, &amp;quot;file_type&amp;quot;: &amp;quot;code&amp;quot;, &amp;quot;community&amp;quot;: 0},
    {&amp;quot;id&amp;quot;: &amp;quot;1&amp;quot;, &amp;quot;label&amp;quot;: &amp;quot;ApiKeyPool&amp;quot;, &amp;quot;file_type&amp;quot;: &amp;quot;code&amp;quot;, &amp;quot;community&amp;quot;: 0},
    {&amp;quot;id&amp;quot;: &amp;quot;2&amp;quot;, &amp;quot;label&amp;quot;: &amp;quot;PlantumlService&amp;quot;, &amp;quot;file_type&amp;quot;: &amp;quot;code&amp;quot;, &amp;quot;community&amp;quot;: 1}
  ],
  &amp;quot;links&amp;quot;: [
    {&amp;quot;source&amp;quot;: &amp;quot;1&amp;quot;, &amp;quot;target&amp;quot;: &amp;quot;0&amp;quot;, &amp;quot;relation&amp;quot;: &amp;quot;uses&amp;quot;, &amp;quot;confidence&amp;quot;: &amp;quot;EXTRACTED&amp;quot;, &amp;quot;weight&amp;quot;: 0.9},
    {&amp;quot;source&amp;quot;: &amp;quot;0&amp;quot;, &amp;quot;target&amp;quot;: &amp;quot;2&amp;quot;, &amp;quot;relation&amp;quot;: &amp;quot;calls&amp;quot;, &amp;quot;confidence&amp;quot;: &amp;quot;INFERRED&amp;quot;, &amp;quot;weight&amp;quot;: 0.7}
  ]
}&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;admonitionblock note&amp;quot;&amp;gt;
&amp;lt;table&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;icon&amp;quot;&amp;gt;
&amp;lt;i class=&amp;quot;fa icon-note&amp;quot; title=&amp;quot;Note&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;
&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;ソースコード (&amp;lt;code&amp;gt;.kt&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;.java&amp;lt;/code&amp;gt;) はローカルで tree-sitter によって解析されます,&amp;lt;strong&amp;gt;控訴不能のLLM&amp;lt;/strong&amp;gt;. ドキュメントファイルのみ (&amp;lt;code&amp;gt;.adoc&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;.md&amp;lt;/code&amp;gt;)必要とするLLMの呼び出し意味抽出のために。したがって`--update`Kotlin コードの編集はほぼ瞬時に完了します。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/table&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_ステップ_2_gradle_プラグインは_knowledge_graph_を_plantuml_に変換します&amp;quot;&amp;gt;ステップ 2 : Gradle プラグインは Knowledge Graph を PlantUML に変換します&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_パイプラインアーキテクチャ&amp;quot;&amp;gt;パイプラインアーキテクチャ&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;プラグイン`com.cheroliv.plantuml`タスクを組み込む`generateKnowledgeGraphDiagram`変換する`graph.json`PlantUML図によって&amp;lt;strong&amp;gt;完全に決定論的&amp;lt;/strong&amp;gt; :&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
skinparam backgroundColor #FEFEFE

participant &amp;quot;Gradle&amp;quot; as G
participant &amp;quot;知識グラフ図生成タスク&amp;quot; as Task
participant &amp;quot;KnowledgeGraphParser&amp;quot; as Parser
participant &amp;quot;KnowledgeGraphRenderer&amp;quot; as Renderer
participant &amp;quot;PlantumlService&amp;quot; as PS

collections &amp;quot;graphify-out/graph.json&amp;quot; as JSON

G -&amp;amp;gt; Task : execute
Task -&amp;amp;gt; JSON : read
Task -&amp;amp;gt; Parser : parse(graph.json)
Parser --&amp;amp;gt; Task : KnowledgeGraph\n(noeuds + arêtes + communautés)
Task -&amp;amp;gt; Renderer : render(graph, filters)
Renderer --&amp;amp;gt; Task : code PlantUML\n(déterministe)
Task -&amp;amp;gt; PS : validateSyntax(plantumlCode)
alt syntaxe valide
    Task -&amp;amp;gt; PS : generateImage → .png
else syntaxe invalide
    Task -&amp;amp;gt; Task : save .puml avec warning
end

@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_内部コンポーネント&amp;quot;&amp;gt;内部コンポーネント&amp;lt;/h3&amp;gt;
&amp;lt;table class=&amp;quot;tableblock frame-all grid-all stretch&amp;quot;&amp;gt;
&amp;lt;colgroup&amp;gt;
&amp;lt;col style=&amp;quot;width: 50%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 50%;&amp;quot;&amp;gt;
&amp;lt;/colgroup&amp;gt;
&amp;lt;thead&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;th class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;コンポーネント&amp;lt;/th&amp;gt;
&amp;lt;th class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;役割&amp;lt;/th&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/thead&amp;gt;
&amp;lt;tbody&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;code&amp;gt;KnowledgeGraphParser&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;パース`graph.json`— サポートする3つの形式：graphify ネイティブ (&amp;lt;code&amp;gt;nodes&amp;lt;/code&amp;gt;+&amp;lt;code&amp;gt;links&amp;lt;/code&amp;gt;), レガシー (&amp;lt;code&amp;gt;communities&amp;lt;/code&amp;gt;), flat. 数値IDsをラベルに解決する。&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;code&amp;gt;KnowledgeGraphRenderer&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;決定的に変換する`KnowledgeGraph`PlantUMLコード。タイプ別にグループ化、パッケージ内のコミュニティ、自動凡例。&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;code&amp;gt;GenerateKnowledgeGraphDiagramTask&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;パース → レンダリング → バリデーション → PNG をオーケストレーションするGradleタスク。Gradleプロパティで設定可能。&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;code&amp;gt;kgmodels.kt&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;データモデル :`KnowledgeGraph`, &amp;lt;code&amp;gt;KnowledgeGraphNode&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;KnowledgeGraphEdge&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;KnowledgeGraphCommunity&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;EdgeType&amp;lt;/code&amp;gt;.&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;code&amp;gt;PlantumlService&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;構文バリデーション + PNG レンダリング（プラグインのすべてのタスクで再利用）。&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/tbody&amp;gt;
&amp;lt;/table&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_レンダリングルール&amp;quot;&amp;gt;レンダリングルール&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;レンダラーは決定的な視覚的規則を適用します：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;table class=&amp;quot;tableblock frame-all grid-all stretch&amp;quot;&amp;gt;
&amp;lt;colgroup&amp;gt;
&amp;lt;col style=&amp;quot;width: 33.3333%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 33.3333%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 33.3334%;&amp;quot;&amp;gt;
&amp;lt;/colgroup&amp;gt;
&amp;lt;thead&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;th class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;エッジタイプ&amp;lt;/th&amp;gt;
&amp;lt;th class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;PlantUML記法&amp;lt;/th&amp;gt;
&amp;lt;th class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;意味&amp;lt;/th&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/thead&amp;gt;
&amp;lt;tbody&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;抽出された&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;code&amp;gt;-&amp;amp;#8594;&amp;lt;/code&amp;gt;(実線, 黒)&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;ソースコードから抽出された関係 (確実性)&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;推論された&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;code&amp;gt;..&amp;amp;gt;&amp;lt;/code&amp;gt;(点線)&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;LLMによる推定関係(信頼スコア)&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;�曖昧&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;code&amp;gt;--x&amp;lt;/code&amp;gt;(赤い点線)&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;あいまいな関係（要確認）&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/tbody&amp;gt;
&amp;lt;/table&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;コミュニティは自動カラーパレットを持つPlantUMLパッケージとしてレンダリングされます。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_ステップ_3_日常での使用&amp;quot;&amp;gt;ステップ 3: 日常での使用&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_完全な図&amp;quot;&amp;gt;完全な図&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;# Générer le diagramme du Knowledge Graph complet
./gradlew generateKnowledgeGraphDiagram&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;出力：&amp;lt;code&amp;gt;diagrams/knowledge-graph/knowledge-graph-full.puml&amp;lt;/code&amp;gt;+&amp;lt;code&amp;gt;.png&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_コミュニティでフィルタリング&amp;quot;&amp;gt;コミュニティでフィルタリング&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;# Une seule communauté
./gradlew generateKnowledgeGraphDiagram \
  -Pplantuml.kg.community=community_0

# Limiter le nombre de noeuds (lisibilité)
./gradlew generateKnowledgeGraphDiagram \
  -Pplantuml.kg.community=community_0 \
  -Pplantuml.kg.maxNodes=15&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_エッジの種類でフィルタリング&amp;quot;&amp;gt;エッジの種類でフィルタリング&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;# Uniquement les relations certaines (EXTRACTED)
./gradlew generateKnowledgeGraphDiagram \
  -Pplantuml.kg.edgeTypes=EXTRACTED

# Relations certaines + inférées
./gradlew generateKnowledgeGraphDiagram \
  -Pplantuml.kg.edgeTypes=EXTRACTED,INFERRED&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_ノードのタイプと信頼度でフィルタリング&amp;quot;&amp;gt;ノードのタイプと信頼度でフィルタリング&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;# Uniquement les classes de code
./gradlew generateKnowledgeGraphDiagram \
  -Pplantuml.kg.nodeTypes=code

# Seuil de confiance minimum (pour les INFERRED)
./gradlew generateKnowledgeGraphDiagram \
  -Pplantuml.kg.minConfidence=0.7&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_カスタマイズされた出力ディレクトリ&amp;quot;&amp;gt;カスタマイズされた出力ディレクトリ&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;./gradlew generateKnowledgeGraphDiagram \
  -Pplantuml.kg.outputDir=docs/architecture&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_プロパティの完全なリファレンス&amp;quot;&amp;gt;プロパティの完全なリファレンス&amp;lt;/h3&amp;gt;
&amp;lt;table class=&amp;quot;tableblock frame-all grid-all stretch&amp;quot;&amp;gt;
&amp;lt;colgroup&amp;gt;
&amp;lt;col style=&amp;quot;width: 33.3333%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 33.3333%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 33.3334%;&amp;quot;&amp;gt;
&amp;lt;/colgroup&amp;gt;
&amp;lt;thead&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;th class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;特性&amp;lt;/th&amp;gt;
&amp;lt;th class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;デフォルト&amp;lt;/th&amp;gt;
&amp;lt;th class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;説明&amp;lt;/th&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/thead&amp;gt;
&amp;lt;tbody&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;code&amp;gt;plantuml.kg.community&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;(すべて)&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;名前でコミュニティをフィルタリングする（部分文字列一致）&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;code&amp;gt;plantuml.kg.edgeTypes&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;em&amp;gt;(すべて)&amp;lt;/em&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;コンマで区切られたエッジの種類 :`EXTRACTED`, &amp;lt;code&amp;gt;INFERRED&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;AMBIGUOUS&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;code&amp;gt;plantuml.kg.minConfidence&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;code&amp;gt;0.0&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;エッジの最小信頼度しきい値&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;code&amp;gt;plantuml.kg.maxNodes&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;em&amp;gt;(無制限)&amp;lt;/em&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;表示する最大のノード数&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;code&amp;gt;plantuml.kg.nodeTypes&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;(皆)&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;カンマで区切られたノードの種類（例`class`, &amp;lt;code&amp;gt;code&amp;lt;/code&amp;gt;)&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;code&amp;gt;plantuml.kg.outputDir&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;code&amp;gt;diagrams/knowledge-graph&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;ファイルの出力ディレクトリ`.puml` et &amp;lt;code&amp;gt;.png&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/tbody&amp;gt;
&amp;lt;/table&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_gradle_ワークフローにおける完全なパイプライン&amp;quot;&amp;gt;Gradle ワークフローにおける完全なパイプライン&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_ワークフローの種類&amp;quot;&amp;gt;ワークフローの種類&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
skinparam backgroundColor #FEFEFE
skinparam ActivityBackgroundColor #E8F4FD
skinparam ActivityDiamondBackgroundColor #FFF3CD
skinparam ActivityBorderColor #2C3E50

start

partition &amp;quot;抽出&amp;quot; {
    :graphify . --no-viz;
    note right: Analyse le code source\ntree-sitter (local, pas de LLM)

    :graphify-out/graph.json;
    note right: Noeuds + arêtes\n+ communautés
}

partition &amp;quot;世代&amp;quot; {
    :./gradlew generateKnowledgeGraphDiagram;
    note right: Pipeline déterministe\nparse → render → validate → PNG

    if (Filtres actifs ?) then (Oui)
        :Appliquer filtres\n(community, edgeTypes,\nmaxNodes, nodeTypes);
    else (Non)
        :Diagramme complet;
    endif

    :diagrams/knowledge-graph/\nknowledge-graph-full.puml\nknowledge-graph-full.png;
}

partition &amp;quot;統合&amp;quot; {
    :git add diagrams/knowledge-graph/;
    :git commit;
    note right: Diagrammes versionnés\ntoujours à jour avec le code
}

stop

@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_開発サイクルへの統合&amp;quot;&amp;gt;開発サイクルへの統合&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;パイプラインは開発の重要な段階に自然に組み込まれます:&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
skinparam backgroundColor #FEFEFE

state &amp;quot;開発&amp;quot; as dev
state &amp;quot;�抽出
グラフ化 . --no-viz&amp;quot; as extract
state &amp;quot;生成
./gradlew generateKnowledgeGraphDiagram&amp;quot; as generate
state &amp;quot;Commit
バージョン管理されたダイアグラム&amp;quot; as commit

[*] --&amp;amp;gt; dev
dev --&amp;amp;gt; extract : Code modifié
extract --&amp;amp;gt; generate : graph.json à jour
generate --&amp;amp;gt; commit : .puml + .png générés
commit --&amp;amp;gt; dev : Diagrammes dans le repo

note right of extract
  Quasi instantané sur du code Kotlin
  (tree-sitter, pas de LLM)
end note

note right of generate
  Déterministe
  Pas de LLM
  Résultat reproductible
end note

@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_インクリメンタルアップデート&amp;quot;&amp;gt;インクリメンタルアップデート&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;コードが変更されるとき、グラフ全体をゼロから再構築するわけではない：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;# Mise à jour incrémentale (fichiers modifiés uniquement)
graphify . --update

# Puis régénérer les diagrammes
./gradlew generateKnowledgeGraphDiagram&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;admonitionblock note&amp;quot;&amp;gt;
&amp;lt;table&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;icon&amp;quot;&amp;gt;
&amp;lt;i class=&amp;quot;fa icon-note&amp;quot; title=&amp;quot;Note&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;
&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;code&amp;gt;--update`再抽出するのは変更されたファイルのみ (SHA256で検出された`graphify-out/cache/&amp;lt;/code&amp;gt;). Kotlin のコードでは、tree-sitter がローカルで動作し LLM を呼び出さないため、ほぼ瞬時に完了します。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/table&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_ドッグフーディングプラグインは自分自身をドキュメント化する&amp;quot;&amp;gt;ドッグフーディング：プラグインは自分自身をドキュメント化する&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;PlantUML プラグインは、プロンプトを図に変換します。さらに、自身の &amp;lt;em&amp;gt;propre&amp;lt;/em&amp;gt; codebase の Knowledge Graph をドキュメント用の図にも変換できます。これは &amp;lt;em&amp;gt;dogfooding&amp;lt;/em&amp;gt; です：プラグインは自身のサービスを利用します。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
skinparam backgroundColor #FEFEFE
skinparam componentStyle rectangle

package &amp;quot;通常のパイプライン\n(ユーザー → 図面)&amp;quot; as normal {
    [Fichier .prompt] as prompt
    [LlmService\n+ ApiKeyPool] as llm1
    [ProcessPlantumlPromptsTask] as task1
    [Diagramme PNG] as out1

    prompt --&amp;amp;gt; task1
    task1 --&amp;amp;gt; llm1
    llm1 --&amp;amp;gt; out1
}

package &amp;quot;パイプラインナレッジグラフ\n(決定論的、LLMなし)&amp;quot; as kg {
    [graphify-out/graph.json] as kgjson
    [KnowledgeGraphParser] as parser
    [KnowledgeGraphRenderer] as renderer
    [PlantumlService] as ps
    [Diagramme PNG\n(documentation du plugin)] as out2

    kgjson --&amp;amp;gt; parser
    parser --&amp;amp;gt; renderer
    renderer --&amp;amp;gt; ps
    ps --&amp;amp;gt; out2
}

package &amp;quot;Pipeline Dogfooding
(LLM → プラグインのドキュメント)&amp;quot; as dogfood {
    [GraphifyPromptAdapter] as gpa
    [Fichiers .prompt\nauto-générés] as auto_prompt
    [LlmService\n+ ApiKeyPool] as llm2
    [ProcessPlantumlPromptsTask] as task2
    [Diagramme PNG\n(documentation LLM)] as out3

    kgjson --&amp;amp;gt; gpa
    gpa --&amp;amp;gt; auto_prompt
    auto_prompt --&amp;amp;gt; task2
    task2 --&amp;amp;gt; llm2
    llm2 --&amp;amp;gt; out3
}

note &amp;quot;同じ LlmService、同じ ApiKeyPool
同じ PlantumlService
— 重複なし&amp;quot; as N

@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;関連付けられた Gradle タスク :&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;table class=&amp;quot;tableblock frame-all grid-all stretch&amp;quot;&amp;gt;
&amp;lt;colgroup&amp;gt;
&amp;lt;col style=&amp;quot;width: 33.3333%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 33.3333%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 33.3334%;&amp;quot;&amp;gt;
&amp;lt;/colgroup&amp;gt;
&amp;lt;thead&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;th class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;タスク&amp;lt;/th&amp;gt;
&amp;lt;th class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;LLM ?&amp;lt;/th&amp;gt;
&amp;lt;th class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;説明&amp;lt;/th&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/thead&amp;gt;
&amp;lt;tbody&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;code&amp;gt;generateKnowledgeGraphDiagram&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;いいえ&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;変形`graph.json`PlantUML（決定論的）で&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;code&amp;gt;generateDiagramDocs&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;はい&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;生成して`.prompt`グラフから、LLMを利用して（ドッグフーディングとして）処理します&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/tbody&amp;gt;
&amp;lt;/table&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;# Documentation déterministe (rapide, pas de LLM)
./gradlew generateKnowledgeGraphDiagram

# Documentation LLM (plus riche, consomme des tokens)
./gradlew generateDiagramDocs&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_なぜそれが決定的なのか_そしてそれが重要である理由&amp;quot;&amp;gt;なぜそれが決定的なのか (そしてそれが重要である理由)&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;パイプラインの重要点`generateKnowledgeGraphDiagram`:&amp;lt;strong&amp;gt;彼はどのLLMも呼び出さない&amp;lt;/strong&amp;gt;. 変換`graph.json`→ PlantUML は純粋な関数。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
skinparam backgroundColor #FEFEFE
skinparam componentStyle rectangle

rectangle &amp;quot;決定論的パイプライン
(generateKnowledgeGraphDiagram)&amp;quot; as det {
    [graph.json] as json
    [KnowledgeGraphParser] as parser
    [KnowledgeGraphRenderer] as renderer
    [PlantUML code] as puml

    json --&amp;amp;gt; parser : parse
    parser --&amp;amp;gt; renderer : KnowledgeGraph
    renderer --&amp;amp;gt; puml : render (fonction pure)
}

rectangle &amp;quot;パイプライン LLM\n(processPlantumlPrompts)&amp;quot; as llm {
    [.prompt] as prompt
    [LlmService] as llmSvc
    [ChatModel] as model
    [PlantUML code] as puml2

    prompt --&amp;amp;gt; llmSvc
    llmSvc --&amp;amp;gt; model : API call
    model --&amp;amp;gt; puml2 : réponse non-déterministe
}

note bottom of det
  Même entrée → même sortie
  Pas de latence réseau
  Pas de coût en tokens
  Reproductible en CI
end note

note bottom of llm
  Même entrée → sortie variable
  Latence réseau (1-5s)
  Coût en tokens
  Nécessite une clave API
end note

@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;具体的な利点：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;table class=&amp;quot;tableblock frame-all grid-all stretch&amp;quot;&amp;gt;
&amp;lt;colgroup&amp;gt;
&amp;lt;col style=&amp;quot;width: 50%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 50%;&amp;quot;&amp;gt;
&amp;lt;/colgroup&amp;gt;
&amp;lt;thead&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;th class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;有利&amp;lt;/th&amp;gt;
&amp;lt;th class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;インパクト&amp;lt;/th&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/thead&amp;gt;
&amp;lt;tbody&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;再現性&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;同じ`graph.json`→ 同じ図. まさに. 毎回。&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;ゼロコスト&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;LLM の呼び出しがない = トークンがない = API の請求書がない&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;ゼロレイテンシ&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;Parse + renderは約100msかかり、1～5秒ではありません。&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;互換性のあるCI&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;APIキーは必要ありません。変動するLLM応答によるフレークなテストはありません。&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;バージョン可能な&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;Le &amp;lt;code&amp;gt;.puml`生成されたものはテキストです。それはできます。`diff&amp;lt;/code&amp;gt;, PR のレビュアー, Git でバージョン管理する。&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/tbody&amp;gt;
&amp;lt;/table&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_パイプライン自体の図&amp;quot;&amp;gt;パイプライン自体の図&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;ループを閉じるために、プラグインによって生成されるパイプライン図をここに示します：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
skinparam backgroundColor #FEFEFE

participant &amp;quot;開発者&amp;quot; as Dev
participant &amp;quot;グレードル&amp;quot; as G
participant &amp;quot;知識グラフダイアグラム生成タスク&amp;quot; as Task
participant &amp;quot;知識グラフパーサー&amp;quot; as Parser
participant &amp;quot;知識グラフレンダラー&amp;quot; as Renderer
participant &amp;quot;プラントUMLサービス&amp;quot; as PS
collections &amp;quot;graphify-out/graph.json&amp;quot; as JSON
collections &amp;quot;diagrams/knowledge-graph/&amp;quot; as Out

Dev -&amp;amp;gt; G : ./gradlew generateKnowledgeGraphDiagram
G -&amp;amp;gt; Task : execute
Task -&amp;amp;gt; JSON : read
Task -&amp;amp;gt; Parser : parse(graph.json)
Parser --&amp;amp;gt; Task : KnowledgeGraph

alt filtres actifs
    Task -&amp;amp;gt; Task : appliquer filtres\n(community, edgeTypes, maxNodes…)
end

Task -&amp;amp;gt; Renderer : render(graph, filters)
Renderer --&amp;amp;gt; Task : code PlantUML

Task -&amp;amp;gt; PS : validateSyntax()
alt valide
    Task -&amp;amp;gt; PS : generateImage()
    PS --&amp;amp;gt; Out : .puml + .png
else invalide
    Task -&amp;amp;gt; Out : .puml (avec warning)
end

@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_プロジェクトガバナンスへの統合&amp;quot;&amp;gt;プロジェクトガバナンスへの統合&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;私たちのプロジェクトでは、このパイプラインはAIエージェントのEAGER/LAZYコンテキスト管理戦略に組み込まれています。Knowledge Graph は、手動のアーキテクチャドキュメントを構造化され、クエリ可能で、自動的に更新されるグラフに置き換えます。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
skinparam backgroundColor #FEFEFE
skinparam componentStyle rectangle

package &amp;quot;EAGER
(いつも充電されている)&amp;quot; as eager {
    [PROMPT_REPRISE.adoc\n(contexte session)] as pr
    [INDEX.adoc\n(vue d&amp;#39;ensemble)] as idx
    [GRAPH_REPORT.adoc\n(~50 lignes)] as gr
}

package &amp;quot;LAZY — 戦略\n(オンデマンド)&amp;quot; as lazy_strat {
    [Méthodologies] as meth
    [Archives sessions] as sessions
}

package &amp;quot;LAZY — Graphify
(ターゲットクエリ)&amp;quot; as lazy_graph {
    [graph.json] as gj
    [Queries\n(query/path/explain)] as queries
}

package &amp;quot;パイプライン PlantUML
(自動生成)&amp;quot; as puml {
    [generateKnowledgeGraphDiagram] as kgTask
    [generateDiagramDocs] as ddTask
    [Diagrammes PNG] as diagrams
}

Agent --&amp;amp;gt; eager : Lit en début de session
Agent ..&amp;amp;gt; lazy_strat : Charge si type détecté
Agent ..&amp;amp;gt; lazy_graph : Query si besoin structurel
kgTask --&amp;amp;gt; diagrams : Déterministe
ddTask --&amp;amp;gt; diagrams : Via LLM

note right of gr
  Condensé du Knowledge Graph
  God nodes + communautés
  Remplace ECOSYSTEM_OVERVIEW
  (225 lignes → 50 lignes)
end note

@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;2つのシステムの結合は補完的です：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;戦略は、いつとどのようにを管理します&amp;lt;/strong&amp;gt;— ガバナンス, ワークフロー, アーカイブ&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;Graphifyは、WHATとWHEREを管理します&amp;lt;/strong&amp;gt;— コードの構造、関係、対象クエリ&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;em&amp;gt;&amp;lt;em&amp;gt;_ セッション戦略は管理する&amp;lt;strong&amp;gt;いつ&amp;lt;/strong&amp;gt; et le &amp;lt;strong&amp;gt;どうやって&amp;lt;/strong&amp;gt;(ガバナンス、ワークフロー、しきい値)、 Graphifyは管理する&amp;lt;strong&amp;gt;何&amp;lt;/strong&amp;gt; et le &amp;lt;strong&amp;gt;どこ&amp;lt;/strong&amp;gt;(コード構造, 関係, ターゲットクエリ). PlantUML パイプラインは&amp;lt;strong&amp;gt;何で&amp;lt;/strong&amp;gt;(決定論的な図、バージョン管理された、常に最新の) &amp;lt;/em&amp;gt;_&amp;lt;/em&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_準備_5分のチェックリスト&amp;quot;&amp;gt;準備 : 5分のチェックリスト&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;table class=&amp;quot;tableblock frame-all grid-all stretch&amp;quot;&amp;gt;
&amp;lt;colgroup&amp;gt;
&amp;lt;col style=&amp;quot;width: 33.3333%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 33.3333%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 33.3334%;&amp;quot;&amp;gt;
&amp;lt;/colgroup&amp;gt;
&amp;lt;thead&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;th class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;(No output, as there is no French text provided to translate)&amp;lt;/th&amp;gt;
&amp;lt;th class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;ステップ&amp;lt;/th&amp;gt;
&amp;lt;th class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;注文&amp;lt;/th&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/thead&amp;gt;
&amp;lt;tbody&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;1&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;Graphifyをインストール&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;code&amp;gt;uv tool install graphifyy&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;2&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;除外を設定&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;作る`.graphifyignore`&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;3&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;Knowledge Graphを抽出&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;code&amp;gt;graphify . --no-viz&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;4&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;図を生成&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;code&amp;gt;./gradlew generateKnowledgeGraphDiagram&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;5&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;結果をコミット&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;code&amp;gt;git add diagrams/knowledge-graph/&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/tbody&amp;gt;
&amp;lt;/table&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;# Script complet en 5 commandes
uv tool install graphifyy
cat &amp;amp;gt; .graphifyignore &amp;amp;lt;&amp;amp;lt; &amp;#39;EOF&amp;#39;
*-context.yml
*.env
build/
.gradle/
EOF
graphify . --no-viz
./gradlew generateKnowledgeGraphDiagram
git add graphify-out/GRAPH_REPORT.adoc graphify-out/graph.json diagrams/knowledge-graph/&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_罠と軽減策&amp;quot;&amp;gt;罠と軽減策&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;table class=&amp;quot;tableblock frame-all grid-all stretch&amp;quot;&amp;gt;
&amp;lt;colgroup&amp;gt;
&amp;lt;col style=&amp;quot;width: 33.3333%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 33.3333%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 33.3334%;&amp;quot;&amp;gt;
&amp;lt;/colgroup&amp;gt;
&amp;lt;thead&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;th class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;�罠&amp;lt;/th&amp;gt;
&amp;lt;th class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;説明&amp;lt;/th&amp;gt;
&amp;lt;th class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;緩和&amp;lt;/th&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/thead&amp;gt;
&amp;lt;tbody&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;グラフが密集しすぎています&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;大きなプロジェクトは数百の読み取り不能なノードを生成する&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;使う`-Pplantuml.kg.maxNodes=30`そしてコミュニティでフィルタリング&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;広すぎる除外&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;ファイルが多すぎます`.graphifyignore`グラフの値を減らす&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;まず、credentials と build を除くだけから始める&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;�矢印の方向&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;INFERREDエッジは曖昧な方向を持つことができる&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;フィルターする`-Pplantuml.kg.edgeTypes=EXTRACTED`確実な関係のみに&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;古いグラフ&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;コードは変わりますが、グラフは再構築されません&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;使用する`graphify . --update`定期的に または git フック`graphify hook install`&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;更新されたコスト&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;増分アップデートはほぼ無料です (tree-sitter local)&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;ドキュメントのみ (`.adoc`LLMのトークンを消費する&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/tbody&amp;gt;
&amp;lt;/table&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_最終的に得られるもの&amp;quot;&amp;gt;最終的に得られるもの&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
skinparam backgroundColor #FEFEFE

rectangle &amp;quot;前に&amp;quot; as avant {
    card &amp;quot;手書きの図表
常に時代遅れ
誰も更新しない&amp;quot; as av1 #FDEDEC
}

rectangle &amp;quot;後&amp;quot; as apres {
    card &amp;quot;自動生成された図
コードと常に最新
Gitでバージョン管理
決定論的かつ再現可能&amp;quot; as ap1 #E8F8E8
}

avant --&amp;amp;gt; apres : graphify . --no-viz\n+ ./gradlew generateKnowledgeGraphDiagram

@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;具体的な利益：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;table class=&amp;quot;tableblock frame-all grid-all stretch&amp;quot;&amp;gt;
&amp;lt;colgroup&amp;gt;
&amp;lt;col style=&amp;quot;width: 50%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 50%;&amp;quot;&amp;gt;
&amp;lt;/colgroup&amp;gt;
&amp;lt;thead&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;th class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;利益&amp;lt;/th&amp;gt;
&amp;lt;th class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;詳細&amp;lt;/th&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/thead&amp;gt;
&amp;lt;tbody&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;常に最新のドキュメンテーション&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;図は現在のコードを反映しており、手動スナップショットではありません。&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;メンテナンスの手間ゼロ&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;�図面は各ビルドごとに再生成されます&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;技術的負債の削減&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;�図を手動で維持する必要はありません。&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;新しい人へのビジュアルコンテキスト&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;新しい開発者は図を見てアーキテクチャを理解する。&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;潜在的なファインチューニング&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;ペア（サブグラフ → ダイアグラム）は AI のトレーニング例です。&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;自動検証&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;`PlantumlService.validateSyntax()`生成された各図を確認します&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;素早いオンボーディング&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;5つのダイアグラム = アーキテクチャの完全なビュー&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/tbody&amp;gt;
&amp;lt;/table&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;em&amp;gt;&amp;lt;em&amp;gt;_ なぜ(_pourquoi&amp;lt;/em&amp;gt;)を持つ人は、すべての(&amp;lt;em&amp;gt;comment&amp;lt;/em&amp;gt;)に耐えることができる。 &amp;lt;/em&amp;gt;__&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;em&amp;gt;pourquoi&amp;lt;/em&amp;gt; : 常に最新の図。 &amp;lt;em&amp;gt;comment&amp;lt;/em&amp;gt; : Gradle パイプライン内の2つのコマンド。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_リンク&amp;quot;&amp;gt;リンク&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;https://github.com/nicholasgasior/graphify&amp;quot;&amp;gt;GitHub上のGraphify&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;https://github.com/cheroliv/plantuml-gradle&amp;quot;&amp;gt;PlantUML Gradle プラグイン&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;/blog/2026/0104_fg_command_super_tips_post.html&amp;quot;&amp;gt;fgコマンドのスーパーヒント&amp;lt;/a&amp;gt;— ターミナルワークフローに関する前の記事&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;</description>
        </item><item>
            <title>fg コマンドのスーパーTips : Ctrl+Z がターミナルセッションを救うとき</title>
            <link >https://cheroliv.com/blog/2026/0104_fg_command_super_tips_post.html</link>
            <pubDate>Sat, 18 Apr 2026 00:00:00 +0000</pubDate>
            <guid isPermaLink="false">blog/2026/0104_fg_command_super_tips_post.html</guid>
            <description>&amp;lt;div id=&amp;quot;toc&amp;quot; class=&amp;quot;toc&amp;quot;&amp;gt;
&amp;lt;div id=&amp;quot;toctitle&amp;quot;&amp;gt;Table des matières&amp;lt;/div&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel1&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_問題端末がビジー&amp;quot;&amp;gt;問題：端末がビジー&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_必須の3つのコマンド&amp;quot;&amp;gt;必須の3つのコマンド&amp;lt;/a&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel2&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_ctrlz_一時停止_sigtstp&amp;quot;&amp;gt;Ctrl+Z — 一時停止 (SIGTSTP)&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_fg_フォアグラウンドで復帰する&amp;quot;&amp;gt;fg — フォアグラウンドで復帰する&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_bg_バックグラウンドで再開&amp;quot;&amp;gt;bg — バックグラウンドで再開&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_jobs_シェルのジョブを一覧表示&amp;quot;&amp;gt;jobs — シェルのジョブを一覧表示&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_シナリオ_1_長いビルド&amp;quot;&amp;gt;シナリオ 1: 長いビルド&amp;lt;/a&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel2&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_ステップバイステップ&amp;quot;&amp;gt;ステップバイステップ&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_シナリオ2_忘れられた編集者&amp;quot;&amp;gt;シナリオ2 : 忘れられた編集者&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_シナリオ3_opencodeプロセスがサスペンド&amp;quot;&amp;gt;シナリオ3: opencodeプロセスがサスペンド&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_シナリオ_4_複数のジョブを同時に管理&amp;quot;&amp;gt;シナリオ 4 : 複数のジョブを同時に管理&amp;lt;/a&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel2&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_ジョブコマンドのサマリー&amp;quot;&amp;gt;ジョブコマンドのサマリー&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_fgbgctrlzctrlc_の違い&amp;quot;&amp;gt;fg、bg、Ctrl+Z、Ctrl+C、&amp;amp;amp; の違い&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_ジョブの完全なライフサイクル&amp;quot;&amp;gt;ジョブの完全なライフサイクル&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_高度なヒント&amp;quot;&amp;gt;高度なヒント&amp;lt;/a&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel2&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_fg_最新の仕事と交互に&amp;quot;&amp;gt;fg 最新の仕事と交互に&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_ジョブをきれいに殺す&amp;quot;&amp;gt;ジョブをきれいに殺す&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_désown_シェルから切り離す&amp;quot;&amp;gt;désown : シェルから切り離す&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_長いプロセスに対して_nohup_と組み合わせる&amp;quot;&amp;gt;長いプロセスに対して nohup と組み合わせる&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_よくある落とし穴と間違い&amp;quot;&amp;gt;よくある落とし穴と間違い&amp;lt;/a&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel2&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_ctrlzとctrlcを混同する&amp;quot;&amp;gt;Ctrl+ZとCtrl+Cを混同する&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_ジョブはシェルにローカルです&amp;quot;&amp;gt;ジョブはシェルにローカルです&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_ジョブはシェルの終了後に生き残らない&amp;quot;&amp;gt;ジョブはシェルの終了後に生き残らない&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_対話型プロセスと_fg&amp;quot;&amp;gt;対話型プロセスと fg&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_サマリーダイアグラム&amp;quot;&amp;gt;サマリーダイアグラム&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_なぜ_fg_が過小評価されているのか&amp;quot;&amp;gt;なぜ fg が過小評価されているのか&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_技術的なメモリ_信号&amp;quot;&amp;gt;技術的なメモリ: 信号&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_結論&amp;quot;&amp;gt;結論&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_参照&amp;quot;&amp;gt;参照&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div id=&amp;quot;preamble&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;読了時間 : 10 minutes&amp;lt;/div&amp;gt;
&amp;lt;p&amp;gt;あなたは始めます`./gradlew build`, ターミナルは3分間ブロックされており、待っている間に他のことをする必要がありますか？新しいタブを開く必要はありません。`Ctrl+Z`プロセスを一時停止する`fg`それはあなたが残した場所に正確に戻します。これは開発者の日常において最も過小評価されているUnixのヒントです。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;dlist&amp;quot;&amp;gt;
&amp;lt;dl&amp;gt;
&amp;lt;dt class=&amp;quot;hdlist1&amp;quot;&amp;gt;目次&amp;lt;/dt&amp;gt;
&amp;lt;dd&amp;gt;
&amp;lt;p&amp;gt;[]&amp;lt;/p&amp;gt;
&amp;lt;/dd&amp;gt;
&amp;lt;/dl&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_問題端末がビジー&amp;quot;&amp;gt;問題：端末がビジー&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;すべての開発者はこの状況を経験したことがある：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;$ ./gradlew build
&amp;amp;gt; Building...&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;ターミナルがフリーズしています。もうコマンドを入力することはできません。そして、ファイルを確認して、起動する必要があります`git status`または、使用中のポートを確認する。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
skinparam backgroundColor #FEFEFE

actor Développeur as dev
participant &amp;quot;ターミナル&amp;quot; as term
participant &amp;quot;Gradle
( プロセス )&amp;quot; as gradle

dev -&amp;amp;gt; term : ./gradlew build
term -&amp;amp;gt; gradle : Lance le build
gradle -&amp;amp;gt; term : Occupe le terminal\n(pas de prompt)
dev -&amp;amp;gt; term : veut taper une commande
term --&amp;amp;gt; dev : ❌ Terminal bloqué

note right of dev
  Le développeur est
  paralysé pendant
  toute la durée du build
end note
@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;ほとんどの開発者は新しいターミナルを開きます。しかし、もっとエレガントで速く、ネイティブなソリューションがあります：ジョブ管理です。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_必須の3つのコマンド&amp;quot;&amp;gt;必須の3つのコマンド&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_ctrlz_一時停止_sigtstp&amp;quot;&amp;gt;Ctrl+Z — 一時停止 (SIGTSTP)&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;`Ctrl+Z`信号を送る`SIGTSTP`フォアグラウンド プロセスに。 プロセスは&amp;lt;strong&amp;gt;中断された&amp;lt;/strong&amp;gt;— 死んでいない — ターミナルはプロンプトを取り戻す。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;$ ./gradlew build
&amp;amp;gt; Building...
^Z
[1]+  Stoppé    ./gradlew build
$&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;括弧の中の数`[1]`です&amp;lt;strong&amp;gt;ジョブ番号&amp;lt;/strong&amp;gt;. Le `+`デフォルトのジョブを示します。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_fg_フォアグラウンドで復帰する&amp;quot;&amp;gt;fg — フォアグラウンドで復帰する&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;`fg`サスペンドされたジョブをフォアグラウンドに戻す。プロセスは、停止した場所から正確に再開される。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;$ fg
./gradlew build
&amp;amp;gt; Building... (reprend où il en était)&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;特定のジョブ番号：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;$ fg %2&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_bg_バックグラウンドで再開&amp;quot;&amp;gt;bg — バックグラウンドで再開&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;`bg`端末をブロックせずにプロセスを再開します。長いビルドに最適です。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;$ bg
[1]+ ./gradlew build &amp;amp;amp;
$&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;Le `&amp;amp;amp;`終わりにあることは、プロセスがバックグラウンドで実行されていることを意味します。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_jobs_シェルのジョブを一覧表示&amp;quot;&amp;gt;jobs — シェルのジョブを一覧表示&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;$ jobs
[1]-  Stoppé    vim README.md
[2]+  En cours   ./gradlew build&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
skinparam backgroundColor #FEFEFE
skinparam defaultFontName sans-serif

state &amp;quot;前景\n(ブロックされたターミナル)&amp;quot; as fg #LightCoral
state &amp;quot;一時停止
(Ctrl+Z)&amp;quot; as stopped #LightYellow
state &amp;quot;背景
(bg)&amp;quot; as bg_ #LightGreen

[*] --&amp;amp;gt; fg : Lance une commande
fg --&amp;amp;gt; stopped : Ctrl+Z\n(SIGTSTP)
stopped --&amp;amp;gt; fg : fg\nreprend en avant-plan
stopped --&amp;amp;gt; bg_ : bg\nreprend en arrière-plan
bg_ --&amp;amp;gt; fg : fg\nramène en avant-plan
fg --&amp;amp;gt; [*] : Commande terminée

note right of stopped
  Le processus est figé
  mais _pas_ tué
end note

note left of bg_
  Le terminal est libre
  le build continue
end note
@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_シナリオ_1_長いビルド&amp;quot;&amp;gt;シナリオ 1: 長いビルド&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;これは最も一般的な使用例です。Gradleのビルドを実行し、ターミナルがブロックされ、他のことをする必要があります。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
skinparam backgroundColor #FEFEFE
autonumber

actor Développeur as dev
participant &amp;quot;ターミナル&amp;quot; as term
participant &amp;quot;Gradle&amp;quot; as gradle
database &amp;quot;状態
プロセス&amp;quot; as state

dev -&amp;amp;gt; term : ./gradlew build
term -&amp;amp;gt; gradle : Lance le build
gradle -&amp;amp;gt; state : En cours (FG)
dev -&amp;amp;gt; term : Ctrl+Z
term -&amp;amp;gt; state : Suspendu (job [1])
term --&amp;amp;gt; dev : Prompt libre $

dev -&amp;amp;gt; term : git status
term --&amp;amp;gt; dev : working tree clean

dev -&amp;amp;gt; term : fg
term -&amp;amp;gt; state : Reprend (FG)
gradle --&amp;amp;gt; dev : Build réussi ✓

note right of state
  Le processus Gradle
  n&amp;#39;a jamais été tué
  Il reprend exactement
  où il s&amp;#39;était arrêté
end note
@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_ステップバイステップ&amp;quot;&amp;gt;ステップバイステップ&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;$ ./gradlew build
&amp;amp;gt; Building...
^Z
[1]+  Stoppé    ./gradlew build

$ git status
On branch main
nothing to commit, working tree clean

$ fg
./gradlew build
&amp;amp;gt; Building...
BUILD SUCCESSFUL in 2m 34s&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_シナリオ2_忘れられた編集者&amp;quot;&amp;gt;シナリオ2 : 忘れられた編集者&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;あなたは…の中にいます`vim`, 他のファイルを確認する必要があります &amp;lt;em&amp;gt;sans&amp;lt;/em&amp;gt; 終了する`vim`.&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;# Dans vim, en mode commande :
:shell
$ cat /path/to/other/file.txt
$ exit
# Retour dans vim&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;しかし、それは重い。それに`Ctrl+Z`, それは即時です :&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;# Dans vim, n&amp;#39;importe quel moment :
Ctrl+Z
[1]+  Stoppé    vim README.md

$ cat /path/to/other/file.txt
# ... lire le fichier ...

$ fg
vim README.md
# Retour exact là où on en était, curseur en place&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
skinparam backgroundColor #FEFEFE
autonumber

actor Développeur as dev
participant &amp;quot;vim&amp;quot; as vim
participant &amp;quot;シェル&amp;quot; as shell

dev -&amp;amp;gt; vim : édition en cours
dev -&amp;amp;gt; vim : Ctrl+Z
vim -&amp;amp;gt; shell : Suspendu (job [1])
dev -&amp;amp;gt; shell : cat autre_fichier.txt
shell --&amp;amp;gt; dev : contenu du fichier
dev -&amp;amp;gt; shell : fg
shell -&amp;amp;gt; vim : Reprend (job [1])
vim --&amp;amp;gt; dev : Curseur exactement\nà la même position

note right of vim
  vim restaure
  intégralement l&amp;#39;état :
  position du curseur,
  buffer, undo stack
end note
@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;(No output?) Actually we need to output something? The instruction: &amp;quot;Translate from fr to ja. &amp;amp;#8230;&amp;amp;#8203; Output only the translated text&amp;quot;. If there is no source text, then there is nothing to translate. So output nothing. We&amp;amp;#8217;ll output an empty line.&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;amp;lt;/think&amp;amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;(Empty)&amp;lt;code&amp;gt;vim`その後、完全にその状態を復元します`fg&amp;lt;/code&amp;gt;: カーソル位置, バッファ内容, 元に戻す履歴 — すべて保持されます。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_シナリオ3_opencodeプロセスがサスペンド&amp;quot;&amp;gt;シナリオ3: opencodeプロセスがサスペンド&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;これがこの記事を書くきっかけとなったシナリオです。あなたは使っています。&amp;lt;code&amp;gt;opencode&amp;lt;/code&amp;gt;(コード上のLLMを操作するCLIツール),そしてプロセスは一時停止されています。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
skinparam backgroundColor #FEFEFE
skinparam defaultFontName sans-serif
skinparam componentStyle rectangle

actor Développeur as dev
participant &amp;quot;opcode
(LLMエージェント)&amp;quot; as agent
participant &amp;quot;シェル&amp;quot; as shell
participant &amp;quot;git&amp;quot; as git

dev -&amp;amp;gt; agent : Session active
agent -&amp;amp;gt; agent : Tour de parole\ndu LLM en cours

note over agent
  Ctrl+Z arrive
  en plein milieu
  d&amp;#39;une analyse de code
end note

dev -&amp;amp;gt; agent : Ctrl+Z
agent -&amp;amp;gt; shell : Suspendu (job [1])
dev -&amp;amp;gt; git : git diff
git --&amp;amp;gt; dev : changements visibles
dev -&amp;amp;gt; shell : fg
shell -&amp;amp;gt; agent : Reprend (job [1])
agent --&amp;amp;gt; dev : Reprend exactement\nl&amp;#39;analyse en cours

note right of agent
  Aucune perte de contexte
  Le LLM reprend sa réponse
  exactement où il en était
end note
@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;$ opencode
# ... session en cours, LLM analyse le code ...
^Z
[1]+  Stoppé    opencode

$ git diff HEAD~1
# vérifier les changements récents

$ fg
opencode
# Le LLM reprend là où il s&amp;#39;était arrêté&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;利点は二重です :&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;olist arabic&amp;quot;&amp;gt;
&amp;lt;ol class=&amp;quot;arabic&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;コンテキストの損失はありません&amp;lt;/strong&amp;gt; : LLM セッション, 会話履歴, 開いているファイル — すべてが保持されます&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;再起動不要&amp;lt;/strong&amp;gt;: opencode を再起動したり、コンテキストを再読み込みしたり、LLM に問題を再説明する必要はありません&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ol&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_シナリオ_4_複数のジョブを同時に管理&amp;quot;&amp;gt;シナリオ 4 : 複数のジョブを同時に管理&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;code&amp;gt;fg&amp;lt;/code&amp;gt; et `bg`複数のプロセスが中断されているときに、特定のプロセスを対象とするジョブ番号を受け付けます。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;$ vim config.yml
^Z
[1]+  Stoppé    vim config.yml

$ ./gradlew test
^Z
[2]+  Stoppé    ./gradlew test

$ htop
^Z
[3]+  Stoppé    htop

$ jobs
[1]   Stoppé    vim config.yml
[2]-  Stoppé    ./gradlew test
[3]+  Stoppé    htop

$ fg %2
./gradlew test
# Le build reprend en avant-plan

$ bg %3
[3] htop &amp;amp;amp;
# htop reprend en arrière-plan&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
skinparam backgroundColor #FEFEFE

rectangle &amp;quot;一時停止中のジョブ&amp;quot; as jobs #LightYellow {
  card &amp;quot;[1] vim config.yml&amp;quot; as j1
  card &amp;quot;[2] ./gradlew テスト&amp;quot; as j2
  card &amp;quot;[3] htop&amp;quot; as j3
}

rectangle &amp;quot;アクション&amp;quot; as actions #LightGreen {
  card &amp;quot;fg %2\n→ 前景&amp;quot; as a1
  card &amp;quot;bg %3\n→ 背景&amp;quot; as a2
  card &amp;quot;fg %1
→ 前景&amp;quot; as a3
}

jobs --&amp;amp;gt; actions : fg/bg + numéro de job
actions --&amp;amp;gt; j2 : Reprend
actions --&amp;amp;gt; j3 : En arrière-plan

note bottom of jobs
  Chaque job conserve
  son état exact
  entre les suspend/resume
end note
@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_ジョブコマンドのサマリー&amp;quot;&amp;gt;ジョブコマンドのサマリー&amp;lt;/h3&amp;gt;
&amp;lt;table class=&amp;quot;tableblock frame-all grid-all stretch&amp;quot;&amp;gt;
&amp;lt;colgroup&amp;gt;
&amp;lt;col style=&amp;quot;width: 20%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 40%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 40%;&amp;quot;&amp;gt;
&amp;lt;/colgroup&amp;gt;
&amp;lt;thead&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;th class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;注文&amp;lt;/th&amp;gt;
&amp;lt;th class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;�効果&amp;lt;/th&amp;gt;
&amp;lt;th class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;例&amp;lt;/th&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/thead&amp;gt;
&amp;lt;tbody&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;code&amp;gt;Ctrl+Z&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;フォアグラウンドプロセスを一時停止&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;送信の`SIGTSTP`&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;code&amp;gt;fg&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;フォアグラウンドでデフォルトのジョブを再開&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;code&amp;gt;fg&amp;lt;/code&amp;gt; ou &amp;lt;code&amp;gt;fg %1&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;code&amp;gt;fg %n&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;ジョブ n をフォアグラウンドで再開&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;code&amp;gt;fg %2&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;code&amp;gt;bg&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;バックグラウンドでデフォルトのジョブを再開します&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;code&amp;gt;bg&amp;lt;/code&amp;gt; ou &amp;lt;code&amp;gt;bg %1&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;code&amp;gt;bg %n&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;ジョブ n をバックグラウンドで再開&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;code&amp;gt;bg %2&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;code&amp;gt;jobs&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;現在のシェルのジョブをリスト&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;code&amp;gt;jobs -l&amp;lt;/code&amp;gt;(PID付き)&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;code&amp;gt;kill %n&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;ジョブ n を終える&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;code&amp;gt;kill %2&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/tbody&amp;gt;
&amp;lt;/table&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_fgbgctrlzctrlc_の違い&amp;quot;&amp;gt;fg、bg、Ctrl+Z、Ctrl+C、&amp;amp;amp; の違い&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;多くの開発者はこれらのメカニズムを混同します。ここに決定的な説明があります。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
skinparam backgroundColor #FEFEFE
skinparam defaultFontName sans-serif

rectangle &amp;quot;**Ctrl+Z**
SIGTSTP&amp;quot; as ctrlz #LightYellow {
  card &amp;quot;プロセスを一時停止します
(まだメモリに残っています)
fg/bg で利用可能&amp;quot; as c1
}

rectangle &amp;quot;**Ctrl+C**\nSIGINT&amp;quot; as ctrlc #LightCoral {
  card &amp;quot;プロセスを殺す
(戻ることはできません)
すべての状態の喪失&amp;quot; as c2
}

rectangle &amp;quot;**および **\n(背景)&amp;quot; as ampersand #LightGreen {
  card &amp;quot;直接起動して
バックグラウンドで
フリーのターミナルすぐに&amp;quot; as c3
}

rectangle &amp;quot;**fg**
(フォアグラウンド)&amp;quot; as fg_ #SkyBlue {
  card &amp;quot;ジョブを持ってきて
フォアグラウンドで一時停止
ターミナルが使用中&amp;quot; as c4
}

rectangle &amp;quot;**bg**\n(背景)&amp;quot; as bg_ #Lavender {
  card &amp;quot;ジョブを再開しろ
バックグラウンドで一時停止中
空きターミナル&amp;quot; as c5
}

ctrlz -right-&amp;amp;gt; fg_ : fg pour reprendre
ctrlz -right-&amp;amp;gt; bg_ : bg pour continuer\nen arrière-plan
ctrlc -right-&amp;amp;gt; c2 : Pas de retour\nprocessus tué

note bottom of ctrlz
  Le processus est **figé**
  mais **pas tué**
end note

note bottom of ampersand
  Alternative : lancer
  ./gradlew build &amp;amp;amp;
  directement en arrière-plan
end note
@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;table class=&amp;quot;tableblock frame-all grid-all stretch&amp;quot;&amp;gt;
&amp;lt;colgroup&amp;gt;
&amp;lt;col style=&amp;quot;width: 16.6666%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 33.3333%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 16.6666%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 33.3335%;&amp;quot;&amp;gt;
&amp;lt;/colgroup&amp;gt;
&amp;lt;thead&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;th class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;ショートカット/コマンド&amp;lt;/th&amp;gt;
&amp;lt;th class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;信号&amp;lt;/th&amp;gt;
&amp;lt;th class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;効果&amp;lt;/th&amp;gt;
&amp;lt;th class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;�戻る？&amp;lt;/th&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/thead&amp;gt;
&amp;lt;tbody&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;code&amp;gt;Ctrl+Z&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;code&amp;gt;SIGTSTP&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;プロセスを一時停止する（凍結、メモリ上）&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;はい :`fg` ou &amp;lt;code&amp;gt;bg&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;code&amp;gt;Ctrl+C&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;code&amp;gt;SIGINT&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;プロセスを終了させる (完了)&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;いいえ : プロセスが破壊されました&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;code&amp;gt;Ctrl+\&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;code&amp;gt;SIGQUIT&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;プロセスを kill + コアダンプ&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;いいえ: 破壊されたプロセス&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;code&amp;gt;commande &amp;amp;amp;&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;—&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;バックグラウンドで直接起動&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;`fg`それを前面に出すために&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/tbody&amp;gt;
&amp;lt;/table&amp;gt;
&amp;lt;div class=&amp;quot;admonitionblock tip&amp;quot;&amp;gt;
&amp;lt;table&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;icon&amp;quot;&amp;gt;
&amp;lt;i class=&amp;quot;fa icon-tip&amp;quot; title=&amp;quot;Tip&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;
&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;content&amp;quot;&amp;gt;
`Ctrl+Z`です&amp;lt;strong&amp;gt;非破壊的&amp;lt;/strong&amp;gt;. プロセスはそのまま固定され、メモリに保持されています。あなたはすぐに再開できますに`fg`これは &amp;lt;em&amp;gt;pause&amp;lt;/em&amp;gt; であって、 &amp;lt;em&amp;gt;stop&amp;lt;/em&amp;gt; ではありません。
&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/table&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_ジョブの完全なライフサイクル&amp;quot;&amp;gt;ジョブの完全なライフサイクル&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
skinparam backgroundColor #FEFEFE
skinparam defaultFontName sans-serif

title シェルジョブの完全なライフサイクル
state &amp;quot;存在しない&amp;quot; as none
state &amp;quot;前景\n(ターミナルを占有します)&amp;quot; as foreground #LightCoral
state &amp;quot;一時停止\n(Ctrl+Z / SIGTSTP)&amp;quot; as suspended #LightYellow
state &amp;quot;背景
(bg または &amp;amp;amp;)&amp;quot; as background #LightGreen
state &amp;quot;完了\n(exit code 0)&amp;quot; as done #LightGray

[*] --&amp;amp;gt; none
none --&amp;amp;gt; foreground : tape une commande
foreground --&amp;amp;gt; suspended : Ctrl+Z
foreground --&amp;amp;gt; done : fin normale

suspended --&amp;amp;gt; foreground : fg
suspended --&amp;amp;gt; background : bg
suspended --&amp;amp;gt; done : kill %n

background --&amp;amp;gt; foreground : fg
background --&amp;amp;gt; done : fin normale\n(en arrière-plan)
background --&amp;amp;gt; suspended : Ctrl+Z\n(si fg puis Ctrl+Z)

done --&amp;amp;gt; [*]

note right of suspended
  L&amp;#39;état suspendu est
  le pivot de tout le
  système de jobs
end note
@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_高度なヒント&amp;quot;&amp;gt;高度なヒント&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_fg_最新の仕事と交互に&amp;quot;&amp;gt;fg 最新の仕事と交互に&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;code&amp;gt;fg`引数なしでは、マークされたジョブが戻ります&amp;lt;/code&amp;gt;+&amp;lt;code&amp;gt;(最新の)。 しかし、あなたはまた使用することもできます&amp;lt;/code&amp;gt;%-`前のジョブを対象にする :&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;$ vim file1.txt
^Z
[1]+  Stoppé    vim file1.txt

$ vim file2.txt
^Z
[2]+  Stoppé    vim file2.txt

$ fg      # ramène job [2] (le plus récent)
$ fg %-   # ramène job [1] (le précédent)&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_ジョブをきれいに殺す&amp;quot;&amp;gt;ジョブをきれいに殺す&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;$ jobs
[1]-  Stoppé    vim config.yml
[2]+  Stoppé    ./gradlew test

$ kill %2       # envoie SIGTERM au job 2
$ kill -9 %1    # envoie SIGKILL au job 1 (force)&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_désown_シェルから切り離す&amp;quot;&amp;gt;désown : シェルから切り離す&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;code&amp;gt;disown`シェルのジョブテーブルからジョブを削除します。プロセスは実行を継続しますが、再度呼び出すことはできません。`fg&amp;lt;/code&amp;gt;:&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;$ ./gradlew build &amp;amp;amp;
[1] 12345

$ disown %1
# Le processus continue mais n&amp;#39;est plus lié au shell
# Ça survives à la fermeture du terminal&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_長いプロセスに対して_nohup_と組み合わせる&amp;quot;&amp;gt;長いプロセスに対して nohup と組み合わせる&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;ターミナルが閉じられたときにプロセスが生き残るように：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;$ nohup ./gradlew build &amp;amp;amp;
[1] 12345
$ disown %1
# Le build continue même si vous fermez le terminal&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
skinparam backgroundColor #FEFEFE
skinparam defaultFontName sans-serif

rectangle &amp;quot;fg&amp;quot; as fg_ #SkyBlue {
  card &amp;quot;最新のジョブを戻す\n(+)&amp;quot; as f1
  card &amp;quot;仕事を狙う
特定 : fg %n&amp;quot; as f2
  card &amp;quot;交互 : fg %-%&amp;quot; as f3
}

rectangle &amp;quot;殺す %n&amp;quot; as kill_ #LightCoral {
  card &amp;quot;SIGTERM (クリーン)&amp;quot; as k1
  card &amp;quot;SIGKILL -9 (強制)&amp;quot; as k2
}

rectangle &amp;quot;縁を切る&amp;quot; as disown #Lavender {
  card &amp;quot;シェルから切り離す
(ログアウト後も生存する)&amp;quot; as d1
}

rectangle &amp;quot;nohup + &amp;amp;amp;&amp;quot; as nohup_ #LightGreen {
  card &amp;quot;免疫プロセス
SIGHUPに対して
(端末の終了に耐える
端末の)&amp;quot; as n1
}

fg_ -right-&amp;amp;gt; kill_ : si faut\nterminer
kill_ -right-&amp;amp;gt; disown_ : ou détacher
nohup_ -left-&amp;amp;gt; fg_ : fg ramène en\navant-plan

note bottom of disown_
  Après disown, fg ne peut
  plus ramener le job
end note
@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_よくある落とし穴と間違い&amp;quot;&amp;gt;よくある落とし穴と間違い&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_ctrlzとctrlcを混同する&amp;quot;&amp;gt;Ctrl+ZとCtrl+Cを混同する&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;これが最も頻繁な間違いです。`Ctrl+C`プロセスを殺す。`Ctrl+Z`それを一時停止します。もしあなたが押すと`Ctrl+C`反射的に、すべての状態が失われます — 開いているファイル、LLMセッション、進行中のビルド。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
skinparam backgroundColor #FEFEFE

rectangle &amp;quot;Ctrl+Z (SIGTSTP)&amp;quot; as z #LightGreen {
  card &amp;quot;メモリ上で凍結しているプロセス&amp;quot; as z1
  card &amp;quot;fg はそれを無傷のまま連れ戻す&amp;quot; as z2
  card &amp;quot;損失なし&amp;quot; as z3
}

rectangle &amp;quot;Ctrl+C (SIGINT)&amp;quot; as c #LightCoral {
  card &amp;quot;プロセス終了&amp;quot; as c1
  card &amp;quot;状態は永久に失われた&amp;quot; as c2
  card &amp;quot;返品はできません&amp;quot; as c3
}

note bottom of z
  Pause → Reprendre
end note

note bottom of c
  Kill → Perdu
end note
@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_ジョブはシェルにローカルです&amp;quot;&amp;gt;ジョブはシェルにローカルです&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;code&amp;gt;jobs&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;fg&amp;lt;/code&amp;gt; et `bg`ジョブは、それらを起動したシェル内でのみ機能します。新しいターミナルを開くと、他のジョブは表示されません。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;# Terminal 1
$ vim file.txt
^Z
[1]+  Stoppé    vim file.txt

# Terminal 2 (nouveau)
$ jobs
# (rien — les jobs sont locaux au shell)&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;システム全体のプロセスを見るには、&amp;lt;code&amp;gt;ps&amp;lt;/code&amp;gt; ou &amp;lt;code&amp;gt;htop&amp;lt;/code&amp;gt;:&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;ps aux | grep vim&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_ジョブはシェルの終了後に生き残らない&amp;quot;&amp;gt;ジョブはシェルの終了後に生き残らない&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;ターミナルを閉じると、一時停止またはバックグラウンドで実行中のすべてのジョブが破棄されます。プロセスが存続するようにするには、使ってください`nohup`+&amp;lt;code&amp;gt;disown&amp;lt;/code&amp;gt;(Empty)&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;$ nohup ./gradlew build &amp;amp;amp;
[1] 12345
$ disown %1
# Fermer le terminal → le build continue&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_対話型プロセスと_fg&amp;quot;&amp;gt;対話型プロセスと fg&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;一部のインタラクティブなプログラムはその後良くない状態になる`Ctrl+Z` + &amp;lt;code&amp;gt;fg&amp;lt;/code&amp;gt;. 稀ですが、起こります：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;シグナルを使用する一部のプログラムは（vim、htop、lessはうまく機能しています`Ctrl+Z`)&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;長時間のネットワークプログラム (ssh、opencode) は通常、正常に取得できます&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;ターミナル (ncurses) を変更するプログラムは、ときどきターミナルを予期しない状態に残すことがあります&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;端末が破損した後の`fg`, 入力して :&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;reset&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_サマリーダイアグラム&amp;quot;&amp;gt;サマリーダイアグラム&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
skinparam backgroundColor #FEFEFE
skinparam defaultFontName sans-serif
skinparam ArrowColor #444444

title &amp;quot;fg — すべてを変えるチップ&amp;quot;

rectangle &amp;quot;問題&amp;quot; as problem #LightCoral {
  card &amp;quot;端末がブロックされました
プロセスによって&amp;quot; as p1
  card &amp;quot;開ける 一つの 新しい\nターミナル = 解決策 重い&amp;quot; as p2
}

rectangle &amp;quot;**解答**&amp;quot; as solution #LightGreen {
  card &amp;quot;Ctrl+Z → 一時停止&amp;quot; as s1
  card &amp;quot;fg → 再開する&amp;quot; as s2
  card &amp;quot;bg → 背景&amp;quot; as s3
  card &amp;quot;jobs → サスペンドされたものを表示&amp;quot; as s4
}

rectangle &amp;quot;利点&amp;quot; as advantages #SkyBlue {
  card &amp;quot;コンテキストの損失なし&amp;quot; as a1
  card &amp;quot;再起動なし&amp;quot; as a2
  card &amp;quot;ターミナル1つで十分です&amp;quot; as a3
}

problem -right-&amp;amp;gt; solution : &amp;quot;Unixネイティブソリューション\n40年間&amp;quot;
solution -right-&amp;amp;gt; advantages : &amp;quot;結果&amp;quot;

note bottom of advantages
  fg n&amp;#39;est pas un tips obscur
  C&amp;#39;est un mécanisme fondamental
  du shell Unix
end note
@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_なぜ_fg_が過小評価されているのか&amp;quot;&amp;gt;なぜ fg が過小評価されているのか&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;ほとんどの最新の開発者は発見する`fg`�遅れたり、あるいは決して起こらないこともあります。 いくつかの理由：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;olist arabic&amp;quot;&amp;gt;
&amp;lt;ol class=&amp;quot;arabic&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;IDEはターミナルを隠す&amp;lt;/strong&amp;gt;: VS Codeは統合ターミナルを提供しますが、複数のタブは`fg`表面的には必要性が低い&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;グラフィカルツールは CLI を置き換える&amp;lt;/strong&amp;gt;ファイルマネージャー、システムモニター、グラフィカルGitクライアント&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;tmux と screen&amp;lt;/strong&amp;gt;: これらのマルチプレクサは同じ問題を異なる方法で解決しますが`fg`よりシンプルで常に利用可能です&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ol&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;しかし、`fg`は：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;olist arabic&amp;quot;&amp;gt;
&amp;lt;ol class=&amp;quot;arabic&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;普遍的&amp;lt;/strong&amp;gt;: POSIXシェルすべてに存在する (bash, zsh, fish&amp;amp;#8230;&amp;amp;#8203;)&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;依存性のない&amp;lt;/strong&amp;gt;: tmuxまたはscreenをインストールする必要はありません&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;スナップショット&amp;lt;/strong&amp;gt;: 2回の打撃 (&amp;lt;code&amp;gt;Ctrl+Z`それから`fg&amp;lt;/code&amp;gt;) 一時停止および再開する&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;コンテキスト保存者&amp;lt;/strong&amp;gt;: プロセスの状態は無傷です&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ol&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
skinparam backgroundColor #FEFEFE
skinparam defaultFontName sans-serif

rectangle &amp;quot;なぜ fg は
過小評価されているのでしょうか？&amp;quot; as why #LightCoral {
  card &amp;quot;ターミナル付きIDE
マルチタブ&amp;quot; as w1
  card &amp;quot;グラフィカルツール
CLIを置き換える&amp;quot; as w2
  card &amp;quot;tmux/screen
問題を解決します
あるいは&amp;quot; as w3
}

rectangle &amp;quot;なぜ fg は
優れているのでしょうか？&amp;quot; as superior #LightGreen {
  card &amp;quot;汎用的 : bash,\nzsh, fish, sh...&amp;quot; as s1
  card &amp;quot;依存なし：\nインストール不要&amp;quot; as s2
  card &amp;quot;2つのキー操作：\nCtrl+Z と fg&amp;quot; as s3
  card &amp;quot;保持されたコンテキスト：
状態損失ゼロ&amp;quot; as s4
}

why -right-&amp;amp;gt; superior : &amp;quot;シンプルさ
いつも勝つ&amp;quot;
@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_技術的なメモリ_信号&amp;quot;&amp;gt;技術的なメモリ: 信号&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;興味のある方へ、関与している信号は以下の通り：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;table class=&amp;quot;tableblock frame-all grid-all stretch&amp;quot;&amp;gt;
&amp;lt;colgroup&amp;gt;
&amp;lt;col style=&amp;quot;width: 14.2857%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 28.5714%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 28.5714%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 28.5715%;&amp;quot;&amp;gt;
&amp;lt;/colgroup&amp;gt;
&amp;lt;thead&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;th class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;信号&amp;lt;/th&amp;gt;
&amp;lt;th class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;名前&amp;lt;/th&amp;gt;
&amp;lt;th class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;送信者&amp;lt;/th&amp;gt;
&amp;lt;th class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;�効果&amp;lt;/th&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/thead&amp;gt;
&amp;lt;tbody&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;2&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;code&amp;gt;SIGINT&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;code&amp;gt;Ctrl+C&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;中断 — プロセスを終了します&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;3&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;code&amp;gt;SIGQUIT&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;code&amp;gt;Ctrl+\&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;コアダンプを伴って終了&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;18&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;code&amp;gt;SIGTSTP&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;code&amp;gt;Ctrl+Z&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;対話的な停止 — プロセスを一時停止&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;19&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;code&amp;gt;SIGCONT&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;code&amp;gt;fg&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;bg&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;続ける — 一時停止されたプロセスを再開する&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;15&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;code&amp;gt;SIGTERM&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;code&amp;gt;kill %n&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;正常な終了&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;9&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;code&amp;gt;SIGKILL&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;code&amp;gt;kill -9 %n&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;強制終了 （インターセプト不可能）&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/tbody&amp;gt;
&amp;lt;/table&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;完全なフロー :&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
skinparam backgroundColor #FEFEFE
skinparam defaultFontName sans-serif

participant &amp;quot;ユーザー&amp;quot; as user
participant &amp;quot;シェル&amp;quot; as shell
participant &amp;quot;プロセス&amp;quot; as proc

user -&amp;amp;gt; shell : Ctrl+Z
shell -&amp;amp;gt; proc : SIGTSTP (signal 18)
note right of proc : Processus figé\nen mémoire

user -&amp;amp;gt; shell : fg
shell -&amp;amp;gt; proc : SIGCONT (signal 19)
note right of proc : Processus reprend\nen avant-plan

user -&amp;amp;gt; shell : bg
shell -&amp;amp;gt; proc : SIGCONT (signal 19)
note right of proc : Processus reprend\nen arrière-plan

user -&amp;amp;gt; shell : Ctrl+C
shell -&amp;amp;gt; proc : SIGINT (signal 2)
note right of proc : Processus terminé\nétat perdu
@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_結論&amp;quot;&amp;gt;結論&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;`fg`これは obscure tips ではない — Unix シェルの基本的なメカニズムで、1970 年代から利用可能です。ほとんどの開発者がこれを無視するのは、私たちの時代の症状です：IDE とマルチプレクサーが私たちを基本から遠ざけている。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;しかし、SSHサーバーにいるとき、ミニマルなターミナルで、あるいは単純に使っているときでも`opencode`そしてLLMはまさに作業中です —&amp;lt;code&amp;gt;Ctrl+Z&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;fg&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;bg&amp;lt;/code&amp;gt;, `jobs`彼らはあなたの親友です。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;em&amp;gt;&amp;lt;em&amp;gt;_ Ctrl+Zで一時停止、fgで再開。これはターミナルの一時停止・再生です。 &amp;lt;/em&amp;gt;_&amp;lt;/em&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_参照&amp;quot;&amp;gt;参照&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;code&amp;gt;man bash&amp;lt;/code&amp;gt;— セクション JOB CONTROL&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;code&amp;gt;man signal&amp;lt;/code&amp;gt;— POSIXシグナルのリスト&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;https://www.gnu.org/software/bash/manual/bash.html#Job-Control&amp;quot;&amp;gt;Bash リファレンスマニュアル — ジョブコントロール&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;https://man7.org/linux/man-pages/man7/signal.7.html&amp;quot;&amp;gt;man 7 signal — Linux のシグナル&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;https://tldp.org/LDP/abs/html/x312743.htm&amp;quot;&amp;gt;高度なBashスクリプティングガイド — ジョブ制御&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;</description>
        </item><item>
            <title>ホームディレクトリでの VS Code : ローカルインストールとフォントのカスタマイズ sudo なし</title>
            <link >https://cheroliv.com/blog/2026/0103_vscode_local_install_custom_fonts_post.html</link>
            <pubDate>Fri, 17 Apr 2026 00:00:00 +0000</pubDate>
            <guid isPermaLink="false">blog/2026/0103_vscode_local_install_custom_fonts_post.html</guid>
            <description>&amp;lt;div id=&amp;quot;toc&amp;quot; class=&amp;quot;toc&amp;quot;&amp;gt;
&amp;lt;div id=&amp;quot;toctitle&amp;quot;&amp;gt;Table des matières&amp;lt;/div&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel1&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_パスの概要&amp;quot;&amp;gt;パスの概要&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_なぜvs_codeはホームに&amp;quot;&amp;gt;なぜ：VS Codeはホームに&amp;lt;/a&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel2&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_システムのインストールの問題&amp;quot;&amp;gt;システムのインストールの問題&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_解決策ローカルインストール&amp;quot;&amp;gt;解決策：ローカルインストール&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_具体的なメリット&amp;quot;&amp;gt;具体的なメリット&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_メインメニューのフォントをカスタマイズ&amp;quot;&amp;gt;メインメニューのフォントをカスタマイズ&amp;lt;/a&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel2&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_事実&amp;quot;&amp;gt;事実&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_技術_cssパッチ_直接&amp;quot;&amp;gt;技術 ： CSSパッチ 直接&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_整合性警告を削除&amp;quot;&amp;gt;整合性警告を削除&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_エクスプローラーウィンドウのフォントをカスタマイズ_闘い&amp;quot;&amp;gt;エクスプローラーウィンドウのフォントをカスタマイズ — 闘い&amp;lt;/a&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel2&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_試み_1_存在しないパラメータ&amp;quot;&amp;gt;試み 1 : 存在しないパラメータ&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_試み2拡張機能_カスタム_css_と_js_ローダー&amp;quot;&amp;gt;試み2：拡張機能 カスタム CSS と JS ローダー&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_罠拡張機能を毎回有効にしなければならない&amp;quot;&amp;gt;�罠：拡張機能を毎回有効にしなければならない&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_試み_3_線が重なる&amp;quot;&amp;gt;試み 3 : 線が重なる&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_解決策zoom_を親コンテナに&amp;quot;&amp;gt;解決策：&amp;lt;code&amp;gt;zoom&amp;lt;/code&amp;gt; を親コンテナに&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_セレクターのまとめと機能するもの&amp;quot;&amp;gt;セレクターのまとめと機能するもの&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_自動更新スクリプト&amp;quot;&amp;gt;自動更新スクリプト&amp;lt;/a&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel2&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_問題&amp;quot;&amp;gt;問題&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_スクリプト_vscode_update_sh&amp;quot;&amp;gt;スクリプト `vscode-update.sh&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_関連ファイル_概要&amp;quot;&amp;gt;関連ファイル — 概要&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_学んだ教訓&amp;quot;&amp;gt;学んだ教訓&amp;lt;/a&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel2&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_ホームへのインストールはすべてを解放する&amp;quot;&amp;gt;ホームへのインストールはすべてを解放する&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_zoom_font_size_リストコンポーネントのために&amp;quot;&amp;gt;zoom` &amp;amp;gt; &amp;lt;code&amp;gt;font-size&amp;lt;/code&amp;gt; リストコンポーネントのために&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_カスタム_css_拡張機能は明示的なアクティベーションを必要とします&amp;quot;&amp;gt;カスタム CSS 拡張機能は明示的なアクティベーションを必要とします。&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_アップデートスクリプトは必須です&amp;quot;&amp;gt;アップデートスクリプトは必須です&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_クイックリファレンス&amp;quot;&amp;gt;クイックリファレンス&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div id=&amp;quot;preamble&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;読了時間 : 8 minutes&amp;lt;/div&amp;gt;
&amp;lt;p&amp;gt;なぜ VS Code をインストールするのか`/opt`または経由で`apt`いつでもそれを自分のホームに置き、IDEを遊び場に変えることができ、決してタイプすることなく`sudo`?以下は、ローカルインストールの後、メニューとファイルエクスプローラーのフォントを拡大するための激しい闘いの物語です。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;dlist&amp;quot;&amp;gt;
&amp;lt;dl&amp;gt;
&amp;lt;dt class=&amp;quot;hdlist1&amp;quot;&amp;gt;癖&amp;lt;/dt&amp;gt;
&amp;lt;dd&amp;gt;
&amp;lt;p&amp;gt;[]&amp;lt;/p&amp;gt;
&amp;lt;/dd&amp;gt;
&amp;lt;/dl&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_パスの概要&amp;quot;&amp;gt;パスの概要&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
skinparam backgroundColor #FEFEFE
skinparam componentStyle rectangle

actor Développeur as dev
actor &amp;quot;opencode\n+ LLM&amp;quot; as agent

package &amp;quot;ユーザーホーム (~)&amp;quot; #LightGreen {
    package &amp;quot;~/apps/&amp;quot; {
        component &amp;quot;VS Code
(tarball)&amp;quot; as vscode #SkyBlue
        component &amp;quot;vscode-update.sh&amp;quot; as script #LightYellow
    }
    package &amp;quot;~/.config/Code/&amp;quot; {
        component &amp;quot;settings.json&amp;quot; as settings #Lavender
    }
    package &amp;quot;~/.vscode-custom-css/&amp;quot; {
        component &amp;quot;custom.css
(ズーム: 1.25)&amp;quot; as customcss #Lavender
    }
}

cloud &amp;quot;code.visualstudio.com&amp;quot; as download

dev --&amp;amp;gt; vscode : Télécharge &amp;amp;amp; installe
dev --&amp;amp;gt; script : Lance mise à jour
script --&amp;amp;gt; download : wget dernière version
script --&amp;amp;gt; vscode : Remplace + re-patch CSS
agent --&amp;amp;gt; settings : Écrit config
agent --&amp;amp;gt; customcss : Écrit zoom CSS
agent --&amp;amp;gt; vscode : Patch workbench CSS

note right of vscode
  Installation dans le home
  = contrôle total sans sudo
end note
@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_なぜvs_codeはホームに&amp;quot;&amp;gt;なぜ：VS Codeはホームに&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_システムのインストールの問題&amp;quot;&amp;gt;システムのインストールの問題&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;VS Code が経由でインストール`apt`, &amp;lt;code&amp;gt;dnf`それから中&amp;lt;/code&amp;gt;/opt`アプリケーションのファイルはroot権限で保護されます。 ネイティブCSSのあらゆる変更は、の`product.json`またはインストールフォルダーが必要です`sudo`。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;しかし、使用するとき&amp;lt;strong&amp;gt;オープンコード&amp;lt;/strong&amp;gt;(tool CLI そのコードでLLMを操作するため), エージェントは次のことができる必要があります：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;設定ファイルに書き込む(&amp;lt;code&amp;gt;~/.config/Code/User/settings.json&amp;lt;/code&amp;gt;) — それは、もうホームにある&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;IDEのアセット（ワークベンチのCSS）を変更する`product.json`) 高度なカスタマイズのために — これは sudo なしではブロックされます&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_解決策ローカルインストール&amp;quot;&amp;gt;解決策：ローカルインストール&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;公式のtarballアーカイブをダウンロードして、それを直接解凍するに`~/apps/`:&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;mkdir -p ~/apps
cd ~/apps
wget &amp;quot;https://code.visualstudio.com/sha/download?build=stable&amp;amp;amp;os=linux-x64&amp;quot; -O vscode.tar.gz
tar -xzf vscode.tar.gz
rm vscode.tar.gz&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;バイナリはその後、&amp;lt;code&amp;gt;~/apps/VSCode-linux-x64/bin/code&amp;lt;/code&amp;gt;。 なし`sudo`読む、編集する、または置き換えるために、どのファイルでも下では必要ありません`~/apps/VSCode-linux-x64/`。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_具体的なメリット&amp;quot;&amp;gt;具体的なメリット&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
skinparam backgroundColor #FEFEFE

rectangle &amp;quot;システムインストール
(/opt, apt, dnf)&amp;quot; #LightCoral {
    card &amp;quot;VS Code の root プロパティ&amp;quot; {
        [CSS du workbench : sudo requis]
        [product.json : sudo requis]
        [Dossier d&amp;#39;install : non modifiable]
    }
}

rectangle &amp;quot;インストール ホーム\n(~/apps)&amp;quot; #LightGreen {
    card &amp;quot;VS Code ユーザーのプロパティ&amp;quot; {
        [CSS du workbench : libre]
        [product.json : libre]
        [Dossier d&amp;#39;install : libre]
        [Script update maison]
    }
}

&amp;quot;システムインストール
(/opt, apt, dnf)&amp;quot; -right-&amp;amp;gt; &amp;quot;インストール ホーム\n(~/apps)&amp;quot; : **Non, merci**\nJe prends le home

note bottom of &amp;quot;インストール ホーム\n(~/apps)&amp;quot;
  L&amp;#39;agent opencode+LLM peut
  modifier les fichiers de l&amp;#39;IDE
  sans aucune élévation de privilèges
end note
@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;table class=&amp;quot;tableblock frame-all grid-all stretch&amp;quot;&amp;gt;
&amp;lt;colgroup&amp;gt;
&amp;lt;col style=&amp;quot;width: 33.3333%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 66.6667%;&amp;quot;&amp;gt;
&amp;lt;/colgroup&amp;gt;
&amp;lt;thead&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;th class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;利点&amp;lt;/th&amp;gt;
&amp;lt;th class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;詳細&amp;lt;/th&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/thead&amp;gt;
&amp;lt;tbody&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;sudo なし&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;IDEのすべてのファイルはユーザーに属します&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;CSSの直接編集&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;パッチできます`workbench.desktop.main.css`特権昇格なし&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;家庭用アップデートスクリプト&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;シンプルなシェルスクリプトが自動的にダウンロード、置換、再パッチを行います&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;隔離&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;システムのインストールは汚染されていない;ロールバック=フォルダーの削除&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/tbody&amp;gt;
&amp;lt;/table&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_メインメニューのフォントをカスタマイズ&amp;quot;&amp;gt;メインメニューのフォントをカスタマイズ&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_事実&amp;quot;&amp;gt;事実&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;メインメニュー(ファイル、編集、表示&amp;amp;#8230;&amp;amp;#8203;)およびドロップダウンのデフォルトフォントが小さすぎます。VS Code にはこれを変更する設定がありません。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_技術_cssパッチ_直接&amp;quot;&amp;gt;技術 ： CSSパッチ 直接&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;ファイルの最後に CSS を追加します`workbench.desktop.main.css` :&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
skinparam backgroundColor #FEFEFE
autonumber

actor Développeur as dev
participant &amp;quot;workbench.desktop\n.main.css&amp;quot; as css
participant &amp;quot;product.json&amp;quot; as product
participant &amp;quot;VSコード&amp;quot; as vscode

== Patch CSS ==
dev -&amp;amp;gt; css : Ajouter règles font-size\n(.menubar-menu-title, etc.)
dev -&amp;amp;gt; vscode : Redémarrer VS Code
vscode -&amp;amp;gt; vscode : Charge le CSS patché
vscode --&amp;amp;gt; dev : Menus et dropdowns en 23px/22px ✓

== Suppression warning ==
vscode --&amp;amp;gt; dev : ⚠️ &amp;quot;インストールが破損しています&amp;quot;
dev -&amp;amp;gt; product : Supprimer clé &amp;quot;チェックサム&amp;quot;\n(python3 -c ...)
dev -&amp;amp;gt; vscode : Redémarrer VS Code
vscode --&amp;amp;gt; dev : Plus de warning ✓

note over css, product
  Deux fichiers dans ~/apps/
  = modifiables sans sudo
end note
@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;CSS_FILE=&amp;quot;$HOME/apps/VSCode-linux-x64/resources/app/out/vs/workbench/workbench.desktop.main.css&amp;quot;

cat &amp;amp;gt;&amp;amp;gt; &amp;quot;$CSS_FILE&amp;quot; &amp;amp;lt;&amp;amp;lt; &amp;#39;EOF&amp;#39;
.menubar-menu-title{font-size:23px!important}
.menubar&amp;amp;gt;.menubar-menu-button{font-size:23px!important}
.monaco-menu-option{font-size:22px!important;line-height:34px!important}
.monaco-menu .action-label:not(.codicon){font-size:22px!important}
.menubar-menu-items-holder .monaco-menu .action-item .action-label{font-size:22px!important}
EOF&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_整合性警告を削除&amp;quot;&amp;gt;整合性警告を削除&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;VS Codeは自身のファイルの変更を検知し、&amp;quot;Your installation is corrupt&amp;quot;というバナーを表示します。これを避けるため、チェックサムを削除します。&amp;lt;code&amp;gt;product.json&amp;lt;/code&amp;gt; :&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-python hljs&amp;quot; data-lang=&amp;quot;python&amp;quot;&amp;gt;import json
product_json = &amp;quot;$HOME/apps/VSCode-linux-x64/resources/app/product.json&amp;quot;
with open(product_json, &amp;#39;r&amp;#39;) as f:
    data = json.load(f)
data.pop(&amp;#39;checksums&amp;#39;, None)
with open(product_json, &amp;#39;w&amp;#39;) as f:
    json.dump(data, f, indent=2)&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;再起動後、警告は表示されなくなり、メニューもようやく読めるようになりました。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_エクスプローラーウィンドウのフォントをカスタマイズ_闘い&amp;quot;&amp;gt;エクスプローラーウィンドウのフォントをカスタマイズ — 闘い&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_試み_1_存在しないパラメータ&amp;quot;&amp;gt;試み 1 : 存在しないパラメータ&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;まずネイティブなパラメータを試す`workbench.tree.fontSize`中`settings.json` :&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-json hljs&amp;quot; data-lang=&amp;quot;json&amp;quot;&amp;gt;{
    &amp;quot;workbench.tree.fontSize&amp;quot;: 20
}&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;結果：&amp;lt;strong&amp;gt;�効果なし&amp;lt;/strong&amp;gt;. この設定はVS Codeには存在しません。認識されない設定が無視されていることの証拠です。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_試み2拡張機能_カスタム_css_と_js_ローダー&amp;quot;&amp;gt;試み2：拡張機能 カスタム CSS と JS ローダー&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;拡張機能をインストールします`be5invis.vscode-custom-css` :&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;~/apps/VSCode-linux-x64/bin/code --install-extension be5invis.vscode-custom-css&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;にCSSファイルを作成します`~/.vscode-custom-css/custom.css`エクスプローラーの要素を対象とするセレクタを使用して :&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-css hljs&amp;quot; data-lang=&amp;quot;css&amp;quot;&amp;gt;.monaco-tree-rows .monaco-tree-row,
.sidebar .monaco-list-row,
.explorer-viewlet .monaco-list-row,
.monaco-list-row .monaco-icon-label {
    font-size: 22px !important;
    line-height: 36px !important;
}&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;そして、このファイルをsettingsで参照します：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-json hljs&amp;quot; data-lang=&amp;quot;json&amp;quot;&amp;gt;{
    &amp;quot;vscode_custom_css.imports&amp;quot;: [
        &amp;quot;file:///home/user/.vscode-custom-css/custom.css&amp;quot;
    ]
}&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;結果：&amp;lt;strong&amp;gt;変更は適用されません&amp;lt;/strong&amp;gt;.&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_罠拡張機能を毎回有効にしなければならない&amp;quot;&amp;gt;�罠：拡張機能を毎回有効にしなければならない&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;拡張機能のドキュメントはこの重要な点についてほとんど言及していない：カスタムCSSを変更するたびに&amp;lt;strong&amp;gt;必ず&amp;lt;/strong&amp;gt;パレットからコマンドを実行して :&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;olist arabic&amp;quot;&amp;gt;
&amp;lt;ol class=&amp;quot;arabic&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;code&amp;gt;Ctrl+Shift+P&amp;lt;/code&amp;gt;→ タイプする&amp;lt;strong&amp;gt;カスタム CSS と JS を有効にする&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;VS Code は再起動を要求します → 受け入れる&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ol&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;この手順がないと、CSS は IDE に絶対に注入されません。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_試み_3_線が重なる&amp;quot;&amp;gt;試み 3 : 線が重なる&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;同じでも`font-size: 22px` et &amp;lt;code&amp;gt;line-height: 36px&amp;lt;/code&amp;gt;, 脚付き文字（g, p, f, b）は隣の行にはみ出します。追加しようとしています。&amp;lt;code&amp;gt;height&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;min-height&amp;lt;/code&amp;gt;:&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-css hljs&amp;quot; data-lang=&amp;quot;css&amp;quot;&amp;gt;.monaco-list-row {
    height: 36px !important;
    min-height: 36px !important;
}&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;結果 :&amp;lt;strong&amp;gt;変更なし&amp;lt;/strong&amp;gt;. VS Code は JavaScript で 行の高さ を 計算 し、CSS の 値 を 上書き します。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_解決策zoom_を親コンテナに&amp;quot;&amp;gt;解決策：&amp;lt;code&amp;gt;zoom&amp;lt;/code&amp;gt; を親コンテナに&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
skinparam backgroundColor #FEFEFE

rectangle &amp;quot;試行1
存在しないパラメータ&amp;quot; #LightCoral {
    card &amp;quot;workbench.tree.fontSize&amp;quot; as t1 {
        [VS Code ignore le paramètre]
    }
}

rectangle &amp;quot;仮2
カスタムCSS+フォントサイズ&amp;quot; #LightYellow {
    card &amp;quot;.monaco-list-row { font-size: 22px }&amp;quot; as t2 {
        [Texte plus grand\nmais lignes superposées]
    }
}

rectangle &amp;quot;試行 3
font-size + line-height + height&amp;quot; #LightYellow {
    card &amp;quot;高さ: 36px !important&amp;quot; as t3 {
        [VS Code override\npar JavaScript]
        [Aucun effet]
    }
}

rectangle &amp;quot;ソリューション
親コンテナのズーム&amp;quot; #LightGreen {
    card &amp;quot;.monaco-list-rows { zoom: 1.25 }&amp;quot; as t4 {
        [Texte + espacement\nproportionnels]
        [Layout JS respecté]
        [✓ Résultat conforme]
    }
}

t1 -down-&amp;amp;gt; t2 : Pas de paramètre ?\nOn essaie le CSS
t2 -down-&amp;amp;gt; t3 : Lignes superposées ?\nOn force la hauteur
t3 -down-&amp;amp;gt; t4 : Override JS ?\nOn utilise zoom

@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;JavaScript のレイアウトに抵抗するのではなく、プロパティを使用します。`zoom`行のコンテナ上 :&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-css hljs&amp;quot; data-lang=&amp;quot;css&amp;quot;&amp;gt;.explorer-viewlet .monaco-list-rows,
.sidebar .monaco-list-rows {
    zoom: 1.25;
}&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;`zoom`コンテナのレンダリングをテキストと間隔の両方を均一に拡大し、VS CodeのJavaScriptエンジンが計算したレイアウトを壊さずに済みます。係数1.25は、おおよそ13pxから16pxへの変更に相当します。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;結果 :&amp;lt;strong&amp;gt;ファイル名がようやく読み取り可能になり、行が適切に間隔を開けて配置されています&amp;lt;/strong&amp;gt;。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_セレクターのまとめと機能するもの&amp;quot;&amp;gt;セレクターのまとめと機能するもの&amp;lt;/h3&amp;gt;
&amp;lt;table class=&amp;quot;tableblock frame-all grid-all stretch&amp;quot;&amp;gt;
&amp;lt;colgroup&amp;gt;
&amp;lt;col style=&amp;quot;width: 25%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 50%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 25%;&amp;quot;&amp;gt;
&amp;lt;/colgroup&amp;gt;
&amp;lt;thead&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;th class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;アプローチ&amp;lt;/th&amp;gt;
&amp;lt;th class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;CSS&amp;lt;/th&amp;gt;
&amp;lt;th class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;結果&amp;lt;/th&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/thead&amp;gt;
&amp;lt;tbody&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;code&amp;gt;font-size`上に&amp;lt;/code&amp;gt;.monaco-list-row`&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;code&amp;gt;font-size: 22px !important&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;テキストは大きいですが、行が重複しています&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;code&amp;gt;line-height&amp;lt;/code&amp;gt;+&amp;lt;code&amp;gt;height`の上に&amp;lt;/code&amp;gt;.monaco-list-row`&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;code&amp;gt;line-height: 36px; height: 36px&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;効果なし (override JS)&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;code&amp;gt;zoom`の上に&amp;lt;/code&amp;gt;.monaco-list-rows`&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;code&amp;gt;zoom: 1.25&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;成功 — テキスト + 比例間隔&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/tbody&amp;gt;
&amp;lt;/table&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_自動更新スクリプト&amp;quot;&amp;gt;自動更新スクリプト&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
skinparam backgroundColor #FEFEFE
autonumber

actor &amp;quot;開発者
または cron&amp;quot; as dev
participant &amp;quot;vscode-update.sh&amp;quot; as script
participant &amp;quot;VSCode ターボール
(code.visualstudio.com)&amp;quot; as remote
participant &amp;quot;~/apps/\nVSCode-linux-x64&amp;quot; as local
participant &amp;quot;~/apps/\nvscode-backup&amp;quot; as backup
participant &amp;quot;ワークベンチ
.desktop.main.css&amp;quot; as css
participant &amp;quot;product.json&amp;quot; as product

dev -&amp;amp;gt; script : ./vscode-update.sh
script -&amp;amp;gt; local : Lire version courante
script -&amp;amp;gt; remote : wget dernière version
script -&amp;amp;gt; script : Comparer versions

alt Version identique
    script --&amp;amp;gt; dev : &amp;quot;すでに最新です！&amp;quot;
else Nouvelle version
    script -&amp;amp;gt; backup : Sauvegarder installation courante\n(horodatée)
    script -&amp;amp;gt; local : rm -rf ancienne installation
    script -&amp;amp;gt; local : mv nouvelle installation
    script -&amp;amp;gt; css : Ajouter patch CSS\n(menubar 23px, dropdown 22px)
    script -&amp;amp;gt; product : Supprimer checksums\n(python3)
    script --&amp;amp;gt; dev : &amp;quot;アップデート完了
1.xx.yy → 1.zz.ww&amp;quot;
end note
@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_問題&amp;quot;&amp;gt;問題&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;VS Code がアップデートされると、インストール フォルダーを置き換えて そして&amp;lt;strong&amp;gt;すべてのCSSパッチを削除&amp;lt;/strong&amp;gt;. 手動で変更を毎回再適用する必要があります。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_スクリプト_vscode_update_sh&amp;quot;&amp;gt;スクリプト `vscode-update.sh&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;作る`~/apps/vscode-update.sh` :&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;#!/bin/bash
set -e

VSCODE_DIR=&amp;quot;$HOME/apps/VSCode-linux-x64&amp;quot;
BACKUP_DIR=&amp;quot;$HOME/apps/vscode-backup&amp;quot;
TEMP_DIR=&amp;quot;/tmp/vscode-update&amp;quot;

MENUBAR_FONT_SIZE=&amp;quot;23px&amp;quot;
DROPDOWN_FONT_SIZE=&amp;quot;22px&amp;quot;

echo &amp;quot;=== VS Code Local Updater ===&amp;quot;

CURRENT_VERSION=$(&amp;quot;$VSCODE_DIR/bin/code&amp;quot; --version 2&amp;amp;gt;/dev/null | head -1)
echo &amp;quot;Current version: $CURRENT_VERSION&amp;quot;

echo &amp;quot;Downloading latest VS Code...&amp;quot;
mkdir -p &amp;quot;$TEMP_DIR&amp;quot;
wget -q &amp;quot;https://code.visualstudio.com/sha/download?build=stable&amp;amp;amp;os=linux-x64&amp;quot; \
    -O &amp;quot;$TEMP_DIR/vscode.tar.gz&amp;quot;

echo &amp;quot;Extracting...&amp;quot;
mkdir -p &amp;quot;$TEMP_DIR/extracted&amp;quot;
tar -xzf &amp;quot;$TEMP_DIR/vscode.tar.gz&amp;quot; -C &amp;quot;$TEMP_DIR/extracted&amp;quot;

NEW_VERSION=$(&amp;quot;$TEMP_DIR/extracted/VSCode-linux-x64/bin/code&amp;quot; \
    --version 2&amp;amp;gt;/dev/null | head -1)
echo &amp;quot;New version: $NEW_VERSION&amp;quot;

if [ &amp;quot;$CURRENT_VERSION&amp;quot; = &amp;quot;$NEW_VERSION&amp;quot; ]; then
    echo &amp;quot;Already up to date!&amp;quot;
    rm -rf &amp;quot;$TEMP_DIR&amp;quot;
    exit 0
fi

echo &amp;quot;Backing up current installation...&amp;quot;
mkdir -p &amp;quot;$BACKUP_DIR&amp;quot;
cp -r &amp;quot;$VSCODE_DIR&amp;quot; &amp;quot;$BACKUP_DIR/VSCode-linux-x64-$(date +%Y%m%d-%H%M%S)&amp;quot;

echo &amp;quot;Updating...&amp;quot;
rm -rf &amp;quot;$VSCODE_DIR&amp;quot;
mv &amp;quot;$TEMP_DIR/extracted/VSCode-linux-x64&amp;quot; &amp;quot;$VSCODE_DIR&amp;quot;
rm -rf &amp;quot;$TEMP_DIR&amp;quot;

CSS_FILE=&amp;quot;$VSCODE_DIR/resources/app/out/vs/workbench/workbench.desktop.main.css&amp;quot;
echo &amp;quot;Re-applying custom CSS patch \
    (menubar=${MENUBAR_FONT_SIZE}, dropdown=${DROPDOWN_FONT_SIZE})...&amp;quot;
cat &amp;amp;gt;&amp;amp;gt; &amp;quot;$CSS_FILE&amp;quot; &amp;amp;lt;&amp;amp;lt; CSSEOF
.menubar-menu-title{font-size:${MENUBAR_FONT_SIZE}!important}\
.menubar&amp;amp;gt;.menubar-menu-button{font-size:${MENUBAR_FONT_SIZE}!important}\
.monaco-menu-option{font-size:${DROPDOWN_FONT_SIZE}!important;\
line-height:34px!important}\
.monaco-menu .action-label:not(.codicon)\
{font-size:${DROPDOWN_FONT_SIZE}!important}\
.menubar-menu-items-holder .monaco-menu .action-item .action-label\
{font-size:${DROPDOWN_FONT_SIZE}!important}
CSSEOF

PRODUCT_JSON=&amp;quot;$VSCODE_DIR/resources/app/product.json&amp;quot;
if [ -f &amp;quot;$PRODUCT_JSON&amp;quot; ]; then
    echo &amp;quot;Removing checksums to prevent integrity warning...&amp;quot;
    python3 -c &amp;quot;
import json
with open(&amp;#39;$PRODUCT_JSON&amp;#39;,&amp;#39;r&amp;#39;) as f: data=json.load(f)
data.pop(&amp;#39;checksums&amp;#39;, None)
with open(&amp;#39;$PRODUCT_JSON&amp;#39;,&amp;#39;w&amp;#39;) as f: json.dump(data,f,indent=2)
print(&amp;#39;Done.&amp;#39;)
&amp;quot;
fi

echo &amp;quot;=== Update complete: $CURRENT_VERSION -&amp;amp;gt; $NEW_VERSION ===&amp;quot;&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;スクリプト :&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;olist arabic&amp;quot;&amp;gt;
&amp;lt;ol class=&amp;quot;arabic&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;最新の安定版をダウンロード&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;現在のバージョンと異なるか確認して&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;現在のインストール（タイムスタンプ付き）を`~/apps/vscode-backup/`&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;インストールフォルダを置き換える&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;再適用&amp;lt;/strong&amp;gt;メインメニューのCSSパッチ&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;チェックサムを削除&amp;lt;/strong&amp;gt; de `product.json`整合性の警告を避けるために&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ol&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;注: Explorerペインのカスタマイズは、Custom CSS拡張機能とファイルを通じて`~/.vscode-custom-css/custom.css`彼らはインストールフォルダー外にいるため、アップデートでも生き残る。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_関連ファイル_概要&amp;quot;&amp;gt;関連ファイル — 概要&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
skinparam backgroundColor #FEFEFE
skinparam componentStyle rectangle

rectangle &amp;quot;VS Code のインストール
(~/apps/VSCode-linux-x64/)&amp;quot; #LightCoral {
    component &amp;quot;workbench.desktop
.main.css&amp;quot; as css #LightCoral
    component &amp;quot;product.json&amp;quot; as product #LightCoral
    component &amp;quot;バイナリ
bin/code&amp;quot; as binary #LightCoral
}

rectangle &amp;quot;ユーザー設定\n(~/.config/Code/)&amp;quot; #LightGreen {
    component &amp;quot;settings.json&amp;quot; as settings #LightGreen
    component &amp;quot;�拡張/&amp;quot; as extensions #LightGreen
}

rectangle &amp;quot;永続的なカスタマイズ
(~/.vscode-custom-css/)&amp;quot; #SkyBlue {
    component &amp;quot;カスタムCSS
(ズーム: 1.25)&amp;quot; as customcss #SkyBlue
}

rectangle &amp;quot;自動化
(~/apps/)&amp;quot; #LightYellow {
    component &amp;quot;vscode-update.sh&amp;quot; as script #LightYellow
    component &amp;quot;vscode-backup/&amp;quot; as backup #LightYellow
}

script ..&amp;amp;gt; css : Re-patch après MAJ
script ..&amp;amp;gt; product : Supprime checksums\naprès MAJ
settings --&amp;amp;gt; customcss : Référence via\nvscode_custom_css.imports
extensions ..&amp;amp;gt; css : Custom CSS Loader\ninjecte custom.css

note bottom of css
  **Ne survit pas** aux mises à jour
  Re-patché par le script
end note

note bottom of customcss
  **Survit** aux mises à jour
  Vit hors du dossier d&amp;#39;installation
end note

note bottom of settings
  **Survit** aux mises à jour
  Vit dans ~/.config/
end note
@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;table class=&amp;quot;tableblock frame-all grid-all stretch&amp;quot;&amp;gt;
&amp;lt;colgroup&amp;gt;
&amp;lt;col style=&amp;quot;width: 28.5714%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 42.8571%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 28.5715%;&amp;quot;&amp;gt;
&amp;lt;/colgroup&amp;gt;
&amp;lt;thead&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;th class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;道&amp;lt;/th&amp;gt;
&amp;lt;th class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;役割&amp;lt;/th&amp;gt;
&amp;lt;th class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;アップデートを生き残る？&amp;lt;/th&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/thead&amp;gt;
&amp;lt;tbody&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;code&amp;gt;~/apps/VSCode-linux-x64/&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;IDEのインストール&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;いいえ (置き換えられた)&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;code&amp;gt;~/apps/VSCode-linux-x64/resources/app/out/vs/workbench/workbench.desktop.main.css&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;WorkbenchのCSS (メニュー, ドロップダウン)&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;いいえ (スクリプトによって再パッチされた)&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;code&amp;gt;~/apps/VSCode-linux-x64/resources/app/product.json&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;整合性チェックサム&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;いいえ (スクリプトによって再クリーニングされました)&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;code&amp;gt;~/apps/vscode-update.sh&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;自動更新スクリプト&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;はい&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;code&amp;gt;~/.config/Code/User/settings.json&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;ユーザー設定 (fontSize, カスタム CSS)&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;はい&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;code&amp;gt;~/.vscode-custom-css/custom.css&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;Explorer用のカスタムCSS（ズーム）&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;はい&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/tbody&amp;gt;
&amp;lt;/table&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_学んだ教訓&amp;quot;&amp;gt;学んだ教訓&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
skinparam backgroundColor #FEFEFE
skinparam defaultFontName sans-serif
skinparam ArrowColor #444444

rectangle &amp;quot;**ローカルインストール**
 ホーム内&amp;quot; as install #LightGreen {
    card &amp;quot;sudoを使わずに
 CSS/configを変更する&amp;quot; as i1
    card &amp;quot;opencode+LLM できます
 すべてを変更&amp;quot; as i2
    card &amp;quot;ロールバック =
 タイムスタンプ付きバックアップを復元する&amp;quot; as i3
}

rectangle &amp;quot;**CSS カスタマイズ**\nズーム vs フォントサイズ&amp;quot; as css #LightYellow {
    card &amp;quot;ズーム &amp;amp;gt; フォントサイズ
 コンポーネントリスト&amp;quot; as c1
    card &amp;quot;Layout JS オーバーライド
 height/line-height&amp;quot; as c2
    card &amp;quot;拡張機能 Custom CSS
 有効化が必要
 手動 (Ctrl+Shift+P)&amp;quot; as c3
}

rectangle &amp;quot;**自動化**
アップデートスクリプト&amp;quot; as auto #LightCoral {
    card &amp;quot;再パッチ CSS
各アップデート後&amp;quot; as a1
    card &amp;quot;チェックサムを削除
 product.json&amp;quot; as a2
    card &amp;quot;タイムスタンプ付きバックアップ
置換前に&amp;quot; as a3
}

install -right-&amp;amp;gt; css : ensuite
css -right-&amp;amp;gt; auto : enfin

note top of install
  Contrôle total sans élévation
  de privilèges
end note

note top of auto
  Sans script, chaque MAJ
  efface les patches CSS
end note
@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_ホームへのインストールはすべてを解放する&amp;quot;&amp;gt;ホームへのインストールはすべてを解放する&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;ローカルインストールの`~/apps`VS Code を完全に制御します :&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;なし`sudo`CSSまたは設定を変更するために&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;opencode+LLMエージェントは、IDEの設定ファイルとアセットに書き込むことができます&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;簡単なロールバック : タイムスタンプ付きバックアップを復元&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_zoom_font_size_リストコンポーネントのために&amp;quot;&amp;gt;zoom` &amp;amp;gt; &amp;lt;code&amp;gt;font-size&amp;lt;/code&amp;gt; リストコンポーネントのために&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;VS Code は JavaScript を使って行の高さを制御します。変更`font-size`レイアウトエンジンが割り当てた高さに変更を加えることができないと、テキストがはみ出します。 プロパティ`zoom`親コンテナ上で全てを比例的に拡大し、この問題を回避します。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_カスタム_css_拡張機能は明示的なアクティベーションを必要とします&amp;quot;&amp;gt;カスタム CSS 拡張機能は明示的なアクティベーションを必要とします。&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;これは「set and forget」な設定ではありません。カスタム CSS ファイルの各変更については、コマンドパレットから「Enable Custom CSS and JS」を再実行する必要があります (&amp;lt;code&amp;gt;Ctrl+Shift+P&amp;lt;/code&amp;gt;)&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_アップデートスクリプトは必須です&amp;quot;&amp;gt;アップデートスクリプトは必須です&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;スクリプトがない場合、VS Codeの更新ごとにワークベンチのCSSパッチが削除されます。スクリプト`vscode-update.sh`ダウンロード、置換、再パッチ、およびチェックサムのクリーニングを自動化する。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_クイックリファレンス&amp;quot;&amp;gt;クイックリファレンス&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;VS Code のダウンロード： &amp;lt;a href=&amp;quot;https://code.visualstudio.com/Download&amp;quot; class=&amp;quot;bare&amp;quot;&amp;gt;https://code.visualstudio.com/Download&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;�拡張機能 カスタム CSS と JS ローダー :`be5invis.vscode-custom-css`&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;問題：VS Code がエクスプローラーのフォント用のネイティブ設定を要求していますhttps://github.com/microsoft/vscode/issues/149[github.com/microsoft/vscode#149]&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;</description>
        </item><item>
            <title>Asciidoctor RevealJSプラグインをKotlinのbuildSrcに移行する : Groovy APIのリバースエンジニアリング</title>
            <link >https://cheroliv.com/blog/2026/0102_migration_gradle_script_to_plugin_post.html</link>
            <pubDate>Thu, 16 Apr 2026 00:00:00 +0000</pubDate>
            <guid isPermaLink="false">blog/2026/0102_migration_gradle_script_to_plugin_post.html</guid>
            <description>&amp;lt;div id=&amp;quot;toc&amp;quot; class=&amp;quot;toc&amp;quot;&amp;gt;
&amp;lt;div id=&amp;quot;toctitle&amp;quot;&amp;gt;Table des matières&amp;lt;/div&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel1&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_背景と目的&amp;quot;&amp;gt;背景と目的&amp;lt;/a&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel2&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_出発点&amp;quot;&amp;gt;出発点&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_目的&amp;quot;&amp;gt;目的&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_最初の障害ruby_gems&amp;quot;&amp;gt;最初の障害：`ruby { gems() }&amp;lt;/a&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel2&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_groovyのシンタックスシュガーが隠しているもの&amp;quot;&amp;gt;Groovyのシンタックスシュガーが隠しているもの&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_メカニズムの分解&amp;quot;&amp;gt;メカニズムの分解&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_3部構成の解決策&amp;quot;&amp;gt;3部構成の解決策&amp;lt;/a&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel2&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_パート_1_rubygems用のivyリポジトリ&amp;quot;&amp;gt;パート 1: rubygems用のIvyリポジトリ&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_パート_2_asciidoctorgems_の依存関係&amp;quot;&amp;gt;パート 2: asciidoctorGems の依存関係&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_パート3_settings_gradle_kts&amp;quot;&amp;gt;パート3: settings.gradle.kts&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_バイトコードによるapiのイントロスペクション&amp;quot;&amp;gt;バイトコードによるAPIのイントロスペクション&amp;lt;/a&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel2&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_なぜ_javap&amp;quot;&amp;gt;なぜ &amp;lt;code&amp;gt;javap&amp;lt;/code&amp;gt; ?&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_タスクの階層&amp;quot;&amp;gt;タスクの階層&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_forkoptionsの発見&amp;quot;&amp;gt;forkOptions`の発見&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_javaforkoptionsのapi_grolifant&amp;quot;&amp;gt;JavaForkOptionsのAPI (grolifant)&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_revealjs拡張&amp;quot;&amp;gt;RevealJS拡張&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_java_ツールチェーンの設定&amp;quot;&amp;gt;Java ツールチェーンの設定&amp;lt;/a&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel2&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_javatoolchainserviceの問題&amp;quot;&amp;gt;JavaToolchainServiceの問題&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_docker自動検出&amp;quot;&amp;gt;Docker自動検出&amp;lt;/a&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel2&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_文脈&amp;quot;&amp;gt;文脈&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_戦略&amp;quot;&amp;gt;戦略&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_最終結果&amp;quot;&amp;gt;最終結果&amp;lt;/a&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel2&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_消費者のビルドスクリプト&amp;quot;&amp;gt;消費者のビルドスクリプト&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_settings_gradle_kts&amp;quot;&amp;gt;settings.gradle.kts&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_罠と解決策のまとめ&amp;quot;&amp;gt;�罠と解決策のまとめ&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_調査方法javap_を使って不明な_api_を読む&amp;quot;&amp;gt;調査方法：javap を使って不明な API を読む&amp;lt;/a&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel2&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_原則&amp;quot;&amp;gt;原則&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_ステップ1gradleキャッシュ内のjarファイルを特定する&amp;quot;&amp;gt;ステップ1：Gradleキャッシュ内のJARファイルを特定する&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_ステップ2_jarのクラスをリストする&amp;quot;&amp;gt;ステップ2: jarのクラスをリストする&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_ステップ_3_クラスを検査する&amp;quot;&amp;gt;ステップ 3 : クラスを検査する&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_ステップ4_階層を上がる&amp;quot;&amp;gt;ステップ4: 階層を上がる&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_ステップ5_不明な型を追跡&amp;quot;&amp;gt;ステップ5: 不明な型を追跡&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_ステップ6プロジェクトの拡張機能を確認する&amp;quot;&amp;gt;ステップ6：プロジェクトの拡張機能を確認する&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_方法のまとめ&amp;quot;&amp;gt;方法のまとめ&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_次のステップ&amp;quot;&amp;gt;次のステップ&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_背景と目的&amp;quot;&amp;gt;背景と目的&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_出発点&amp;quot;&amp;gt;出発点&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;プロジェクト`slider-gradle`Gradleプラグインを介してAsciiDocファイルからReveal.jsプレゼンテーションを生成します`org.asciidoctor.jvm.revealjs`. 主要タスクの設定`asciidoctorRevealJs`ルートのビルドスクリプトに直接存在していた`build.gradle.kts`[space]&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-kotlin hljs&amp;quot; data-lang=&amp;quot;kotlin&amp;quot;&amp;gt;plugins { id(&amp;quot;org.asciidoctor.jvm.revealjs&amp;quot;) }

apply&amp;amp;lt;slides.SlidesPlugin&amp;amp;gt;()

project.tasks.getByName&amp;amp;lt;AsciidoctorJRevealJSTask&amp;amp;gt;(TASK_ASCIIDOCTOR_REVEALJS) {
    repositories { ruby { gems() } }
    revealjs {
        version = &amp;quot;3.1.0&amp;quot;
        templateGitHub {
            setOrganisation(&amp;quot;hakimel&amp;quot;)
            setRepository(&amp;quot;reveal.js&amp;quot;)
            setTag(&amp;quot;3.9.1&amp;quot;)
        }
    }
    revealjsOptions {
        // ... configuration complète
    }
}&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_目的&amp;quot;&amp;gt;目的&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;この構成すべてを移動する`buildSrc/src/main/kotlin/slides/SlidesPlugin.kt`コンシューマーのbuildscriptが次のように簡略化されるように：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-kotlin hljs&amp;quot; data-lang=&amp;quot;kotlin&amp;quot;&amp;gt;apply&amp;amp;lt;slides.SlidesPlugin&amp;amp;gt;()&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;プラグインは完全に自立している必要があります: それは自身でプラグインの依存関係を適用し、リポジトリを設定し、Ruby の gems を管理します。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_最初の障害ruby_gems&amp;quot;&amp;gt;最初の障害：`ruby { gems() }&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_groovyのシンタックスシュガーが隠しているもの&amp;quot;&amp;gt;Groovyのシンタックスシュガーが隠しているもの&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;ライン`repositories { ruby { gems() } }`これはbuildscript実行コンテキストでのみ利用可能なGroovy DSL拡張です。buildSrcからアクセス可能な静的なKotlin APIとして存在しません。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;それを呼び出そうとしてから`SlidesPlugin.kt`, コンパイルはすぐに失敗します。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_メカニズムの分解&amp;quot;&amp;gt;メカニズムの分解&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;Gradleキャッシュの分析後 (&amp;lt;code&amp;gt;~/.gradle/caches/modules-2/files-2.1/rubygems/&amp;lt;/code&amp;gt;), ファイルの中で見つかる`ivy-3.1.0.xml`:&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-xml hljs&amp;quot; data-lang=&amp;quot;xml&amp;quot;&amp;gt;&amp;amp;lt;artifact type=&amp;#39;gem&amp;#39; url=&amp;#39;https://rubygems.org/gems/asciidoctor-revealjs-3.1.0.gem&amp;#39; /&amp;amp;gt;&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;`ruby { gems() }`実際に行っていた&amp;lt;strong&amp;gt;3つの異なる操作&amp;lt;/strong&amp;gt;:&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;olist arabic&amp;quot;&amp;gt;
&amp;lt;ol class=&amp;quot;arabic&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;指しているIvyリポジトリを保存する`https://rubygems.org/gems/`&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;グループを除外する`rubygems`Maven リポジトリで競合を避けるため&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;ジェムを設定に保存`asciidoctorGems`JRubyがランタイムでそれをロードするように&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ol&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;これらの三つの責任は、Kotlinで個別に再実装しなければなりません。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_3部構成の解決策&amp;quot;&amp;gt;3部構成の解決策&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_パート_1_rubygems用のivyリポジトリ&amp;quot;&amp;gt;パート 1: rubygems用のIvyリポジトリ&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-kotlin hljs&amp;quot; data-lang=&amp;quot;kotlin&amp;quot;&amp;gt;project.repositories.mavenCentral() {
    content { excludeGroup(&amp;quot;rubygems&amp;quot;) }
}
project.repositories.ivy {
    url = project.uri(&amp;quot;https://rubygems.org/gems/&amp;quot;)
    patternLayout { artifact(&amp;quot;[module]-[revision].gem&amp;quot;) } &amp;lt;i class=&amp;quot;conum&amp;quot; data-value=&amp;quot;1&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;b&amp;gt;(1)&amp;lt;/b&amp;gt;
    metadataSources { artifact() }
    content { includeGroup(&amp;quot;rubygems&amp;quot;) }
}&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;colist arabic&amp;quot;&amp;gt;
&amp;lt;table&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td&amp;gt;&amp;lt;i class=&amp;quot;conum&amp;quot; data-value=&amp;quot;1&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;b&amp;gt;1&amp;lt;/b&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td&amp;gt;拡張`.gem`ハードコーディングする必要がある。&amp;lt;code&amp;gt;[ext]`デフォルトで解決する&amp;lt;/code&amp;gt;.jar`, これがエラーを引き起こす`Resource missing`.&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/table&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;admonitionblock note&amp;quot;&amp;gt;
&amp;lt;table&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;icon&amp;quot;&amp;gt;
&amp;lt;i class=&amp;quot;fa icon-note&amp;quot; title=&amp;quot;Note&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;
&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;content&amp;quot;&amp;gt;
Ivy リポジトリは直接上に宣言されます`project.repositories`そしてブロックの中にない`repositories { }`このブロックのレシーバーではないから`RepositoryHandler`Gradle標準だが、grolifantというAPIは拡張機能と互換性がない`ivy`Kotlin DSL.
&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/table&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_パート_2_asciidoctorgems_の依存関係&amp;quot;&amp;gt;パート 2: asciidoctorGems の依存関係&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;プラグイン`org.asciidoctor.jvm.gems`最初に適用する必要があります—これにより設定が作成されます`asciidoctorGems`とタスク`asciidoctorGemsPrepare`&amp;amp;lt;/think&amp;amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-kotlin hljs&amp;quot; data-lang=&amp;quot;kotlin&amp;quot;&amp;gt;project.plugins.apply(&amp;quot;org.asciidoctor.jvm.gems&amp;quot;)
project.plugins.apply(&amp;quot;org.asciidoctor.jvm.revealjs&amp;quot;) &amp;lt;i class=&amp;quot;conum&amp;quot; data-value=&amp;quot;1&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;b&amp;gt;(1)&amp;lt;/b&amp;gt;

project.dependencies {
    add(&amp;quot;asciidoctorGems&amp;quot;, &amp;quot;rubygems:asciidoctor-revealjs:3.1.0@gem&amp;quot;) &amp;lt;i class=&amp;quot;conum&amp;quot; data-value=&amp;quot;2&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;b&amp;gt;(2)&amp;lt;/b&amp;gt;
}&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;適用順序は重要です:`gems`前に`revealjs`. &amp;amp;lt;2&amp;amp;gt; 修飾語`@gem`依存関係に正しい拡張子を強制する。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_パート3_settings_gradle_kts&amp;quot;&amp;gt;パート3: settings.gradle.kts&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;`dependencyResolutionManagement`中に`settings.gradle.kts`プロジェクトが自身のリポジトリを宣言できるようにする必要があります :&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-kotlin hljs&amp;quot; data-lang=&amp;quot;kotlin&amp;quot;&amp;gt;@Suppress(&amp;quot;UnstableApiUsage&amp;quot;)
dependencyResolutionManagement {
    repositoriesMode.set(RepositoriesMode.PREFER_PROJECT)
}&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;この行がなければ、Gradleはプラグインで宣言されたリポジトリを無視し、gemの解決が失敗します。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_バイトコードによるapiのイントロスペクション&amp;quot;&amp;gt;バイトコードによるAPIのイントロスペクション&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_なぜ_javap&amp;quot;&amp;gt;なぜ &amp;lt;code&amp;gt;javap&amp;lt;/code&amp;gt; ?&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;プラグイン`asciidoctor-gradle-jvm-slides`バージョンです`4.0.0-alpha.1`. そのドキュメントは存在しないか不完全です。 唯一の信頼できるソースは、コンパイル済みクラスの直接検査です。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_タスクの階層&amp;quot;&amp;gt;タスクの階層&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;javap -p -classpath asciidoctor-gradle-jvm-slides-4.0.0-alpha.1.jar \
  org.asciidoctor.gradle.jvm.slides.AsciidoctorJRevealJSTask&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;結果 :&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-none hljs&amp;quot;&amp;gt;public class AsciidoctorJRevealJSTask
  extends org.asciidoctor.gradle.jvm.AbstractAsciidoctorTask
  implements org.asciidoctor.gradle.base.slides.SlidesToExportAware&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_forkoptionsの発見&amp;quot;&amp;gt;forkOptions`の発見&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;�検査しながら`AbstractAsciidoctorTask`:&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;javap -p -classpath asciidoctor-gradle-jvm-4.0.0-alpha.1.jar \
  org.asciidoctor.gradle.jvm.AbstractAsciidoctorTask | grep -i &amp;quot;fork\|exec\|jvm&amp;quot;&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;見つかります：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-none hljs&amp;quot;&amp;gt;final org.ysb33r.grolifant.api.v4.JavaForkOptions javaForkOptions;
public void forkOptions(org.gradle.api.Action&amp;amp;lt;org.ysb33r.grolifant.api.v4.JavaForkOptions&amp;amp;gt;);
public static final org.asciidoctor.gradle.base.process.ProcessMode JAVA_EXEC;&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_javaforkoptionsのapi_grolifant&amp;quot;&amp;gt;JavaForkOptionsのAPI (grolifant)&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;`javaLauncher`このタスクには存在しません。 実際のAPIは`org.ysb33r.grolifant.api.v4.JavaForkOptions`公開 :&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-none hljs&amp;quot;&amp;gt;public void executable(java.lang.Object);  &amp;lt;i class=&amp;quot;conum&amp;quot; data-value=&amp;quot;1&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;b&amp;gt;(1)&amp;lt;/b&amp;gt;
public void setExecutable(java.lang.Object);&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;colist arabic&amp;quot;&amp;gt;
&amp;lt;table&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td&amp;gt;&amp;lt;i class=&amp;quot;conum&amp;quot; data-value=&amp;quot;1&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;b&amp;gt;1&amp;lt;/b&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td&amp;gt;方法`executable(Object)`代入を置き換える`executable = &amp;amp;#8230;&amp;amp;#8203;`コンパイルされない (`val`再割り当てすることはできません)。&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/table&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_revealjs拡張&amp;quot;&amp;gt;RevealJS拡張&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;`revealjs { }`タスクの方法ではなく、&amp;lt;strong&amp;gt;プロジェクトの拡張&amp;lt;/strong&amp;gt; :&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;javap -p -classpath asciidoctor-gradle-jvm-slides-4.0.0-alpha.1.jar \
  org.asciidoctor.gradle.jvm.slides.RevealJSExtension&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;アクセスするには：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-kotlin hljs&amp;quot; data-lang=&amp;quot;kotlin&amp;quot;&amp;gt;project.extensions.getByType&amp;amp;lt;RevealJSExtension&amp;amp;gt;().apply {
    version = &amp;quot;3.1.0&amp;quot;
    templateGitHub {
        setOrganisation(&amp;quot;hakimel&amp;quot;)
        setRepository(&amp;quot;reveal.js&amp;quot;)
        setTag(&amp;quot;3.9.1&amp;quot;)
    }
}&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_java_ツールチェーンの設定&amp;quot;&amp;gt;Java ツールチェーンの設定&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_javatoolchainserviceの問題&amp;quot;&amp;gt;JavaToolchainServiceの問題&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;`JavaToolchainService`プロジェクトの拡張ではありません。次の呼び出しは失敗します :&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-kotlin hljs&amp;quot; data-lang=&amp;quot;kotlin&amp;quot;&amp;gt;// ERREUR : Extension of type &amp;#39;JavaToolchainService&amp;#39; does not exist
project.extensions.getByType&amp;amp;lt;JavaToolchainService&amp;amp;gt;()&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;良いAPIは`serviceOf`:&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-kotlin hljs&amp;quot; data-lang=&amp;quot;kotlin&amp;quot;&amp;gt;import org.gradle.kotlin.dsl.support.serviceOf

project.tasks.getByName&amp;amp;lt;AsciidoctorJRevealJSTask&amp;amp;gt;(TASK_ASCIIDOCTOR_REVEALJS) {
    setInProcess(&amp;quot;JAVA_EXEC&amp;quot;)
    forkOptions {
        executable(
            project.serviceOf&amp;amp;lt;JavaToolchainService&amp;amp;gt;()
                .launcherFor {
                    languageVersion.set(JavaLanguageVersion.of(17))
                    vendor.set(JvmVendorSpec.ADOPTIUM)
                }
                .get()
                .executablePath
                .asFile
                .absolutePath
        )
    }
}&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_docker自動検出&amp;quot;&amp;gt;Docker自動検出&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_文脈&amp;quot;&amp;gt;文脈&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;Asciidoctor/JRuby プラグインは Java 17 が必要です。buildSrc における Kotlin 2.0.x は Java 25 をサポートしていません。(バージョン パーサーがクラッシュします。&amp;lt;code&amp;gt;&amp;quot;25.0.2&amp;quot;&amp;lt;/code&amp;gt;)したがって、Gradle デーモンは Java 17 上で実行するか、または Docker を使用する必要があります。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_戦略&amp;quot;&amp;gt;戦略&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;olist arabic&amp;quot;&amp;gt;
&amp;lt;ol class=&amp;quot;arabic&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;Docker が利用可能 → コンテナを介した実行`eclipse-temurin:17`(デフォルトの動作)&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;Docker がない + Java 17 → ローカル実行&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;Dockerが不在 + Java &amp;amp;gt; 17 → 明示的なエラー&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ol&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-kotlin hljs&amp;quot; data-lang=&amp;quot;kotlin&amp;quot;&amp;gt;val isDockerAvailable = try {
    Runtime.getRuntime().exec(arrayOf(&amp;quot;docker&amp;quot;, &amp;quot;info&amp;quot;)).waitFor() == 0
} catch (e: Exception) {
    false
}

val javaVersion = JavaVersion.current().majorVersion.toInt()

when {
    isDockerAvailable -&amp;amp;gt; project.tasks.register&amp;amp;lt;Exec&amp;amp;gt;(TASK_ASCIIDOCTOR_REVEALJS) {
        group = GROUP_TASK_SLIDER
        description = &amp;quot;Slider settings and generation (via Docker)&amp;quot;
        dependsOn(TASK_CLEAN_SLIDES_BUILD)
        finalizedBy(TASK_DASHBOARD_SLIDES_BUILD)
        commandLine(
            &amp;quot;docker&amp;quot;, &amp;quot;run&amp;quot;, &amp;quot;--rm&amp;quot;,
            &amp;quot;-v&amp;quot;, &amp;quot;${project.rootDir.absolutePath}:/workspace&amp;quot;,
            &amp;quot;-v&amp;quot;, &amp;quot;${System.getProperty(&amp;quot;user.home&amp;quot;)}/.gradle:/root/.gradle&amp;quot;,
            &amp;quot;-w&amp;quot;, &amp;quot;/workspace&amp;quot;,
            &amp;quot;eclipse-temurin:17&amp;quot;,
            &amp;quot;./gradlew&amp;quot;, TASK_ASCIIDOCTOR_REVEALJS
        )
        workingDir = project.rootDir
    }
    javaVersion == 17 -&amp;amp;gt; {
        project.repositories.mavenCentral() {
            content { excludeGroup(&amp;quot;rubygems&amp;quot;) }
        }
        project.repositories.ivy {
            url = project.uri(&amp;quot;https://rubygems.org/gems/&amp;quot;)
            patternLayout { artifact(&amp;quot;[module]-[revision].gem&amp;quot;) }
            metadataSources { artifact() }
            content { includeGroup(&amp;quot;rubygems&amp;quot;) }
        }
        project.extensions.getByType&amp;amp;lt;RevealJSExtension&amp;amp;gt;().apply {
            version = &amp;quot;3.1.0&amp;quot;
            templateGitHub {
                setOrganisation(&amp;quot;hakimel&amp;quot;)
                setRepository(&amp;quot;reveal.js&amp;quot;)
                setTag(&amp;quot;3.9.1&amp;quot;)
            }
        }
        project.tasks.getByName&amp;amp;lt;AsciidoctorJRevealJSTask&amp;amp;gt;(TASK_ASCIIDOCTOR_REVEALJS) {
            setInProcess(&amp;quot;JAVA_EXEC&amp;quot;)
            forkOptions {
                executable(
                    project.serviceOf&amp;amp;lt;JavaToolchainService&amp;amp;gt;()
                        .launcherFor {
                            languageVersion.set(JavaLanguageVersion.of(17))
                            vendor.set(JvmVendorSpec.ADOPTIUM)
                        }
                        .get()
                        .executablePath
                        .asFile
                        .absolutePath
                )
            }
            // ... reste de la configuration
        }
    }
    else -&amp;amp;gt; error(
        &amp;quot;Docker est requis pour exécuter $TASK_ASCIIDOCTOR_REVEALJS &amp;quot; +
        &amp;quot;avec Java $javaVersion. Installez Docker ou utilisez Java 17.&amp;quot;
    )
}&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_最終結果&amp;quot;&amp;gt;最終結果&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_消費者のビルドスクリプト&amp;quot;&amp;gt;消費者のビルドスクリプト&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-kotlin hljs&amp;quot; data-lang=&amp;quot;kotlin&amp;quot;&amp;gt;apply&amp;amp;lt;slides.SlidesPlugin&amp;amp;gt;()&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;それだけです。 プラグインがすべての責任を負います。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_settings_gradle_kts&amp;quot;&amp;gt;settings.gradle.kts&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-kotlin hljs&amp;quot; data-lang=&amp;quot;kotlin&amp;quot;&amp;gt;pluginManagement {
    repositories {
        mavenLocal()
        gradlePluginPortal()
    }
}

plugins {
    id(&amp;quot;org.gradle.toolchains.foojay-resolver-convention&amp;quot;) version &amp;quot;0.8.0&amp;quot;
}

@Suppress(&amp;quot;UnstableApiUsage&amp;quot;)
dependencyResolutionManagement {
    repositoriesMode.set(RepositoriesMode.PREFER_PROJECT)
}

rootProject.name = &amp;quot;slider-gradle&amp;quot;&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_罠と解決策のまとめ&amp;quot;&amp;gt;�罠と解決策のまとめ&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;table class=&amp;quot;tableblock frame-all grid-all stretch&amp;quot;&amp;gt;
&amp;lt;colgroup&amp;gt;
&amp;lt;col style=&amp;quot;width: 25%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 37.5%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 37.5%;&amp;quot;&amp;gt;
&amp;lt;/colgroup&amp;gt;
&amp;lt;thead&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;th class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;問題&amp;lt;/th&amp;gt;
&amp;lt;th class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;原因&amp;lt;/th&amp;gt;
&amp;lt;th class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;解決策&amp;lt;/th&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/thead&amp;gt;
&amp;lt;tbody&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;`ruby { gems() }`Kotlinでは利用できません&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;Groovy DSL専用の拡張&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;3つの別々のメカニズム : repo Ivy + exclusion Maven +&amp;lt;code&amp;gt;asciidoctorGems&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;Gradleは`.jar`代わりの`.gem`&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;`[ext]`解決するで`jar`デフォルト&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;ハードコーダー`.gem`Ivy パターン + 修飾子`@gem`&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;code&amp;gt;ivy { }`でコンパイルされない`repositories { }&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;コトリンDSLと互換性のないレシーバーグルリファント&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;直接呼び出し`project.repositories.ivy { }`&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;`javaLauncher`未解決&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;存在しないプロパティに`AsciidoctorJRevealJSTask`&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;code&amp;gt;setInProcess(&amp;quot;JAVA_EXEC&amp;quot;)&amp;lt;/code&amp;gt;(Note: No output)&amp;lt;code&amp;gt;forkOptions { executable(&amp;amp;#8230;&amp;amp;#8203;) }&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;`executable = &amp;amp;#8230;&amp;amp;#8203;`コンパイルされません&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;財産`val`中に`JavaForkOptions`グロリファント&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;方法`executable(Object)`代わりに&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;code&amp;gt;JavaToolchainService`経由で見つからない`extensions&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;これは Gradle のサービスであり、拡張機能ではありません。&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;code&amp;gt;project.serviceOf&amp;amp;lt;JavaToolchainService&amp;amp;gt;()&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;`revealjs { }`タスクでは未解決&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;プロジェクトの拡張、タスクの方法ではない&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;code&amp;gt;project.extensions.getByType&amp;amp;lt;RevealJSExtension&amp;amp;gt;()&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;Build は Java 25 でクラッシュします&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;Kotlin 2.0.xは2桁のJavaバージョンをパースしません&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;自動Docker検出 + Java 17 フォールバック&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/tbody&amp;gt;
&amp;lt;/table&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_調査方法javap_を使って不明な_api_を読む&amp;quot;&amp;gt;調査方法：javap を使って不明な API を読む&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_原則&amp;quot;&amp;gt;原則&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;ドキュメントが欠如しているか、または不完全な場合、バイトコードが真実のソースとなります。 &amp;lt;code&amp;gt;javap`はJDKの標準ツールで、ファイルをデコンパイルします。&amp;lt;/code&amp;gt;.class`� 読みやすい Java のシグニチャー, ソースコードを必要としない。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_ステップ1gradleキャッシュ内のjarファイルを特定する&amp;quot;&amp;gt;ステップ1：Gradleキャッシュ内のJARファイルを特定する&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;グラドル ダウンロードする すべての依存関係 に`~/.gradle/caches/modules-2/files-2.1/`。 最初のステップは、検査したいクラスを含む jar ファイルを見つけることです：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;find ~/.gradle/caches -name &amp;quot;asciidoctor-gradle-jvm-slides*.jar&amp;quot; 2&amp;amp;gt;/dev/null&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;結果 :&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-none hljs&amp;quot;&amp;gt;/home/user/.gradle/caches/modules-2/files-2.1/org.asciidoctor/
asciidoctor-gradle-jvm-slides/4.0.0-alpha.1/.../
asciidoctor-gradle-jvm-slides-4.0.0-alpha.1.jar&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_ステップ2_jarのクラスをリストする&amp;quot;&amp;gt;ステップ2: jarのクラスをリストする&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;クラスを検査する前に、それがjar内に確かに存在することを確認します :&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;jar tf asciidoctor-gradle-jvm-slides-4.0.0-alpha.1.jar | grep -i &amp;quot;RevealJS\|revealjs&amp;quot;&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;これはすべての利用可能なクラスを示します： &amp;lt;code&amp;gt;AsciidoctorJRevealJSTask&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;RevealJSExtension&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;RevealJSOptions&amp;lt;/code&amp;gt;, など&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_ステップ_3_クラスを検査する&amp;quot;&amp;gt;ステップ 3 : クラスを検査する&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;javap -p -classpath asciidoctor-gradle-jvm-slides-4.0.0-alpha.1.jar \
org.asciidoctor.gradle.jvm.slides.AsciidoctorJRevealJSTask&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;オプション`-p`すべてのメンバー、プライベートなものも含めて表示します。 結果はすぐにキー行を表示します：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-none hljs&amp;quot;&amp;gt;public class AsciidoctorJRevealJSTask
extends org.asciidoctor.gradle.jvm.AbstractAsciidoctorTask&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_ステップ4_階層を上がる&amp;quot;&amp;gt;ステップ4: 階層を上がる&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;タスクは伸ばす`AbstractAsciidoctorTask`その後、それを検査します まずその jar を特定して：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;find ~/.gradle/caches -name &amp;quot;asciidoctor-gradle-jvm-[0-9]*.jar&amp;quot; 2&amp;amp;gt;/dev/null

javap -p -classpath asciidoctor-gradle-jvm-4.0.0-alpha.1.jar \
org.asciidoctor.gradle.jvm.AbstractAsciidoctorTask | grep -i &amp;quot;fork\|exec\|jvm\|java&amp;quot;&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;そこで見つける`forkOptions`, &amp;lt;code&amp;gt;JAVA_EXEC&amp;lt;/code&amp;gt;, et &amp;lt;code&amp;gt;javaForkOptions&amp;lt;/code&amp;gt; タイプの`org.ysb33r.grolifant.api.v4.JavaForkOptions`。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_ステップ5_不明な型を追跡&amp;quot;&amp;gt;ステップ5: 不明な型を追跡&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;`JavaForkOptions`これは不明なgrolifantクラスです。そのjarファイルを見つけます：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;find ~/.gradle/caches -name &amp;quot;grolifant*.jar&amp;quot; 2&amp;amp;gt;/dev/null&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;次に、それを検査します：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;javap -p -classpath grolifant40-legacy-api-2.0.0-alpha.6.jar \
org.ysb33r.grolifant.api.v4.JavaForkOptions&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;そこにはある`executable(java.lang.Object)&amp;lt;code&amp;gt;— 呼び出すべき正しいメソッド, 対照的に`executable = &amp;amp;#8230;&amp;amp;#8203;`これはプロパティだからコンパイルできない`val&amp;lt;/code&amp;gt;.&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_ステップ6プロジェクトの拡張機能を確認する&amp;quot;&amp;gt;ステップ6：プロジェクトの拡張機能を確認する&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;ために`revealjs { }`, 質問は：これはタスクの方法ですか？ またはプロジェクトの拡張ですか？検査の`AsciidoctorJRevealJSTask` 方法を示さない`revealjs`. その後、検査します`RevealJSExtension` :&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;javap -p -classpath asciidoctor-gradle-jvm-slides-4.0.0-alpha.1.jar \
org.asciidoctor.gradle.jvm.slides.RevealJSExtension | head -5&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-none hljs&amp;quot;&amp;gt;public class RevealJSExtension implements groovy.lang.GroovyObject {
public static final java.lang.String NAME;&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;の存在`NAME`それがプロジェクトに登録された拡張機能であることを確認します。 経由でアクセス可能`project.extensions.getByType&amp;amp;lt;RevealJSExtension&amp;amp;gt;()`.&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_方法のまとめ&amp;quot;&amp;gt;方法のまとめ&amp;lt;/h3&amp;gt;
&amp;lt;table class=&amp;quot;tableblock frame-all grid-all stretch&amp;quot;&amp;gt;
&amp;lt;colgroup&amp;gt;
&amp;lt;col style=&amp;quot;width: 25%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 75%;&amp;quot;&amp;gt;
&amp;lt;/colgroup&amp;gt;
&amp;lt;thead&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;th class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;ステップ&amp;lt;/th&amp;gt;
&amp;lt;th class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;アクション&amp;lt;/th&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/thead&amp;gt;
&amp;lt;tbody&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;1&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;code&amp;gt;find ~/.gradle/caches -name &amp;quot;*.jar&amp;quot;&amp;lt;/code&amp;gt;— jar を特定する&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;2&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;code&amp;gt;jar tf jar.jar | grep NomClasse&amp;lt;/code&amp;gt;— クラスが存在することを確認する&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;3&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;code&amp;gt;javap -p -classpath jar.jar NomCompletClasse&amp;lt;/code&amp;gt;— クラスを検査する&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;4&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;識別する`extends`そして階層を上がる&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;5&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;未知の型を自身のJAR内で追跡する&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;6&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;探す`NAME`プロジェクトの拡張を特定するために&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/tbody&amp;gt;
&amp;lt;/table&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;このメソッドは、ドキュメント化されていない API を持つ任意の Gradle プラグインに適用されます。 または、アルファバージョンが既存のドキュメントに合わなくなった。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_次のステップ&amp;quot;&amp;gt;次のステップ&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;この buildSrc プラグインは、Gradle Plugin Portal または Maven Local に公開された独立したプロジェクトに抽出されます。消費者側の buildscript は次のようになります：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-kotlin hljs&amp;quot; data-lang=&amp;quot;kotlin&amp;quot;&amp;gt;plugins { id(&amp;quot;slides&amp;quot;) version &amp;quot;1.0.0&amp;quot; }&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;Et &amp;lt;code&amp;gt;settings.gradle.kts`最小限に抑えられ、参照なしで`foojay-resolver-convention&amp;lt;/code&amp;gt;, JDKのプロビジョニングはプラグイン自身によって管理され、または前提条件としてドキュメント化されている。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;</description>
        </item><item>
            <title>アーキテクチャポートフォリオ JBake - ビジョンとユースケース</title>
            <link >https://cheroliv.com/blog/2026/0101_jbake_portfolio_post.html</link>
            <pubDate>Thu, 15 Jan 2026 00:00:00 +0000</pubDate>
            <guid isPermaLink="false">blog/2026/0101_jbake_portfolio_post.html</guid>
            <description>&amp;lt;div id=&amp;quot;toc&amp;quot; class=&amp;quot;toc&amp;quot;&amp;gt;
&amp;lt;div id=&amp;quot;toctitle&amp;quot;&amp;gt;Table des matières&amp;lt;/div&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel1&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_建築的ビジョン&amp;quot;&amp;gt;建築的ビジョン&amp;lt;/a&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel2&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_指導原理&amp;quot;&amp;gt;指導原理&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_戦略的な選択_ポートフォリオ用のasciidoc&amp;quot;&amp;gt;戦略的な選択 : ポートフォリオ用のAsciiDoc&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_データモデル&amp;quot;&amp;gt;データモデル&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_詳細なユースケース&amp;quot;&amp;gt;詳細なユースケース&amp;lt;/a&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel2&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_uc1_ポートフォリオにアイテムを追加する&amp;quot;&amp;gt;UC1 : ポートフォリオにアイテムを追加する&amp;lt;/a&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel3&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_定格フラックス&amp;quot;&amp;gt;定格フラックス&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_作成するファイルのテンプレート&amp;quot;&amp;gt;作成するファイルのテンプレート&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_検証ポイント&amp;quot;&amp;gt;検証ポイント&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_uc2_ポートフォリオから要素を削除&amp;quot;&amp;gt;UC2 : ポートフォリオから要素を削除&amp;lt;/a&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel3&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_名義フラックス&amp;quot;&amp;gt;名義フラックス&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_代替戦略アーカイブ&amp;quot;&amp;gt;代替戦略:アーカイブ&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_リソースのクリーンアップ&amp;quot;&amp;gt;リソースのクリーンアップ&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_uc3_下書き非公開に設定&amp;quot;&amp;gt;UC3 : 下書き（非公開）に設定&amp;lt;/a&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel3&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_定格フラックス_2&amp;quot;&amp;gt;定格フラックス&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_可能な状態&amp;quot;&amp;gt;可能な状態&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_典型的な使用例&amp;quot;&amp;gt;典型的な使用例&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_テンプレーティングアーキテクチャ&amp;quot;&amp;gt;テンプレーティングアーキテクチャ&amp;lt;/a&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel2&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_再利用可能なテンプレートの戦略&amp;quot;&amp;gt;再利用可能なテンプレートの戦略&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_データ抽出パターン&amp;quot;&amp;gt;データ抽出パターン&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_命名規則&amp;quot;&amp;gt;命名規則&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_公開ワークフロー&amp;quot;&amp;gt;公開ワークフロー&amp;lt;/a&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel2&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_開発パイプライン&amp;quot;&amp;gt;開発パイプライン&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_環境&amp;quot;&amp;gt;環境&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_拡張性&amp;quot;&amp;gt;拡張性&amp;lt;/a&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel2&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_新しい属性の追加&amp;quot;&amp;gt;新しい属性の追加&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_高度な分類&amp;quot;&amp;gt;高度な分類&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_ベストプラクティス&amp;quot;&amp;gt;ベストプラクティス&amp;lt;/a&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel2&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_ファイルの整理&amp;quot;&amp;gt;ファイルの整理&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_コンテンツ管理&amp;quot;&amp;gt;コンテンツ管理&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_パフォーマンス&amp;quot;&amp;gt;パフォーマンス&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_結論&amp;quot;&amp;gt;結論&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_建築的ビジョン&amp;quot;&amp;gt;建築的ビジョン&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_指導原理&amp;quot;&amp;gt;指導原理&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;アーキテクチャは、*関心の分離*という原則に基づいています :&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;Contenu&amp;lt;/strong&amp;gt; : 構造化されたAsciiDocファイル（メタデータが豊富）&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;プレゼンテーション&amp;lt;/strong&amp;gt; : テンプレート Thymeleaf 再利用可能&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;データ&amp;lt;/strong&amp;gt; : JBake によって AsciiDoc の属性から自動抽出されたモデル&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;Style&amp;lt;/strong&amp;gt; : ビジュアルの一貫性のための Bootstrap 5&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_戦略的な選択_ポートフォリオ用のasciidoc&amp;quot;&amp;gt;戦略的な選択 : ポートフォリオ用のAsciiDoc&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;なぜ AsciiDoc ですか？&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;table class=&amp;quot;tableblock frame-all grid-all stretch&amp;quot;&amp;gt;
&amp;lt;colgroup&amp;gt;
&amp;lt;col style=&amp;quot;width: 33.3333%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 66.6667%;&amp;quot;&amp;gt;
&amp;lt;/colgroup&amp;gt;
&amp;lt;thead&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;th class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;基準&amp;lt;/th&amp;gt;
&amp;lt;th class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;利点&amp;lt;/th&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/thead&amp;gt;
&amp;lt;tbody&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;整合性&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;ブログ記事と同じフォーマット&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;メタデータ&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;構造化および拡張可能な属性 (&amp;lt;code&amp;gt;project-*&amp;lt;/code&amp;gt;)&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;保守性&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;シンプルなテキスト編集、Gitでバージョン管理可能&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;�柔軟性&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;�豊富なコンテンツ（表、コード、画像）を含むことがあります&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;テンプレーティング&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;JBakeは自動的にThymeleafの属性を抽出します&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/tbody&amp;gt;
&amp;lt;/table&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_データモデル&amp;quot;&amp;gt;データモデル&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;各ポートフォリオプロジェクトはAsciiDocドキュメントです：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;ヘッダーのメタデータ&amp;lt;/strong&amp;gt; : 構造化された情報 (クライアント, 期間, テクノロジー, など)&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;ドキュメント本文&amp;lt;/strong&amp;gt; : ナラティブな説明, 課題, 解決策, 結果&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;カスタム属性&amp;lt;/strong&amp;gt; : プレフィックス付き`project-*`自動抽出のために&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
skinparam backgroundColor #FEFEFE
skinparam handwritten false

class ProjetAsciiDoc {
  +titre: String
  +jbake-type: &amp;quot;プロジェクト&amp;quot;
  +jbake-status: published|draft
  +jbake-date: Date
  +jbake-tags: List&amp;amp;lt;String&amp;amp;gt;
  --
  +project-category: String
  +project-client: String
  +project-duration: String
  +project-role: String
  +project-thumbnail: String
  +project-gallery: List&amp;amp;lt;String&amp;amp;gt;
  +project-tech-stack: String
  +project-highlights: List&amp;amp;lt;String&amp;amp;gt;
  +project-demo-url: String
  +project-github-url: String
  --
  +body: HTML (converti)
}

class JBakeEngine {
  +parse(asciidoc)
  +extractMetadata()
  +convertToHTML()
}

class ThymeleafTemplate {
  +portfolio.html
  +project.html
  +partials/project-card.html
}

class PortfolioPage {
  +published_projects: List
  +filtres: categories
}

ProjetAsciiDoc --&amp;amp;gt; JBakeEngine : parse
JBakeEngine --&amp;amp;gt; ThymeleafTemplate : fournit données
ThymeleafTemplate --&amp;amp;gt; PortfolioPage : génère
@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_詳細なユースケース&amp;quot;&amp;gt;詳細なユースケース&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_uc1_ポートフォリオにアイテムを追加する&amp;quot;&amp;gt;UC1 : ポートフォリオにアイテムを追加する&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;sect3&amp;quot;&amp;gt;
&amp;lt;h4 id=&amp;quot;_定格フラックス&amp;quot;&amp;gt;定格フラックス&amp;lt;/h4&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
skinparam backgroundColor #FEFEFE
actor Développeur as dev
participant &amp;quot;編集者
テキスト&amp;quot; as editor
participant &amp;quot;ファイル
AsciiDoc&amp;quot; as file
participant &amp;quot;JBake\nエンジン&amp;quot; as jbake
participant &amp;quot;サイト
静的&amp;quot; as site

dev -&amp;amp;gt; editor : Créer nouveau fichier
activate editor
editor -&amp;amp;gt; file : portfolio/nouveau-projet.adoc
activate file

dev -&amp;amp;gt; editor : Rédiger en-tête avec métadonnées\n(titre, type=project, status=published,\nattributs project-*)
dev -&amp;amp;gt; editor : Rédiger contenu narratif\n(contexte, défis, solutions)
dev -&amp;amp;gt; editor : Ajouter images dans assets/img/portfolio/

editor -&amp;amp;gt; file : Sauvegarder
deactivate editor

dev -&amp;amp;gt; jbake : Lancer build (jbake -b)
activate jbake
jbake -&amp;amp;gt; file : Lire et parser
jbake -&amp;amp;gt; jbake : Extraire métadonnées
jbake -&amp;amp;gt; jbake : Convertir AsciiDoc → HTML
jbake -&amp;amp;gt; jbake : Appliquer template project.html
jbake -&amp;amp;gt; jbake : Ajouter à la liste portfolio.html
jbake -&amp;amp;gt; site : Générer pages statiques
deactivate jbake

dev -&amp;amp;gt; site : Vérifier résultat
activate site
site --&amp;amp;gt; dev : Afficher projet
deactivate site
@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect3&amp;quot;&amp;gt;
&amp;lt;h4 id=&amp;quot;_作成するファイルのテンプレート&amp;quot;&amp;gt;作成するファイルのテンプレート&amp;lt;/h4&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;開発者は作成します`content/portfolio/nom-projet.adoc`標準化された構造：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;すべての必須属性を備えたヘッダー&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;標準化されたセクション (コンテキスト、課題、ソリューション、結果)&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;画像の一貫した命名法&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect3&amp;quot;&amp;gt;
&amp;lt;h4 id=&amp;quot;_検証ポイント&amp;quot;&amp;gt;検証ポイント&amp;lt;/h4&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;必須属性は存在します (&amp;lt;code&amp;gt;jbake-type&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;jbake-status&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;project-thumbnail&amp;lt;/code&amp;gt;)&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;参照されている画像が存在する中に`assets/img/portfolio/`&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;JBakeのビルドはエラーなく成功します&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;プロジェクトがポートフォリオページに表示されます&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;プロジェクトの個別ページが正しく表示されます&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_uc2_ポートフォリオから要素を削除&amp;quot;&amp;gt;UC2 : ポートフォリオから要素を削除&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;sect3&amp;quot;&amp;gt;
&amp;lt;h4 id=&amp;quot;_名義フラックス&amp;quot;&amp;gt;名義フラックス&amp;lt;/h4&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
skinparam backgroundColor #FEFEFE
actor Développeur as dev
participant &amp;quot;システム
ファイル&amp;quot; as fs
participant &amp;quot;JBake
エンジン&amp;quot; as jbake
participant &amp;quot;サイト
静的&amp;quot; as site
database &amp;quot;キャッシュ
JBake&amp;quot; as cache

dev -&amp;amp;gt; fs : Supprimer portfolio/projet-ancien.adoc
activate fs
fs --&amp;amp;gt; dev : Fichier supprimé
deactivate fs

dev -&amp;amp;gt; fs : (Optionnel) Supprimer images associées\nassets/img/portfolio/projet-ancien-*
activate fs
fs --&amp;amp;gt; dev : Images supprimées
deactivate fs

dev -&amp;amp;gt; cache : Nettoyer cache JBake
activate cache
cache --&amp;amp;gt; dev : Cache vidé
deactivate cache

dev -&amp;amp;gt; jbake : Rebuild complet (jbake -b)
activate jbake
jbake -&amp;amp;gt; jbake : Scanner content/portfolio/
jbake -&amp;amp;gt; jbake : Projet absent → non généré
jbake -&amp;amp;gt; jbake : Régénérer portfolio.html\n(sans le projet supprimé)
jbake -&amp;amp;gt; site : Déployer nouveau build
deactivate jbake

dev -&amp;amp;gt; site : Vérifier
activate site
site --&amp;amp;gt; dev : Projet absent de la liste
deactivate site
@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect3&amp;quot;&amp;gt;
&amp;lt;h4 id=&amp;quot;_代替戦略アーカイブ&amp;quot;&amp;gt;代替戦略:アーカイブ&amp;lt;/h4&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;完全に削除する代わりに、フォルダを作成することが可能です`content/portfolio/archive/`:&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;ファイルを削除する代わりに移動する&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;簡単に復元できる&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;Gitの履歴をもっと分かりやすく保つ&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect3&amp;quot;&amp;gt;
&amp;lt;h4 id=&amp;quot;_リソースのクリーンアップ&amp;quot;&amp;gt;リソースのクリーンアップ&amp;lt;/h4&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;�孤児画像を確認する中に`assets/img/portfolio/`&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;他のプロジェクトで参照されていない画像を削除&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;JBakeのキャッシュをクリアして、幽霊参照を避けてください。&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_uc3_下書き非公開に設定&amp;quot;&amp;gt;UC3 : 下書き（非公開）に設定&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;sect3&amp;quot;&amp;gt;
&amp;lt;h4 id=&amp;quot;_定格フラックス_2&amp;quot;&amp;gt;定格フラックス&amp;lt;/h4&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
skinparam backgroundColor #FEFEFE
actor Développeur as dev
participant &amp;quot;ファイル\nAsciiDoc&amp;quot; as file
participant &amp;quot;JBake\nエンジン&amp;quot; as jbake
participant &amp;quot;サイト\n静的&amp;quot; as site

dev -&amp;amp;gt; file : Ouvrir portfolio/projet.adoc
activate file

dev -&amp;amp;gt; file : Modifier attribut\n:jbake-status: published\n↓\n:jbake-status: draft

file --&amp;amp;gt; dev : Sauvegardé
deactivate file

dev -&amp;amp;gt; jbake : Rebuild (jbake -b)
activate jbake
jbake -&amp;amp;gt; file : Parser le fichier
jbake -&amp;amp;gt; jbake : Détecter status=draft
jbake -&amp;amp;gt; jbake : Exclure de published_projects
jbake -&amp;amp;gt; jbake : Ne pas créer page publique
note right
  Le projet existe toujours
  mais n&amp;#39;est pas publié
end note
jbake -&amp;amp;gt; site : Générer site (sans ce projet)
deactivate jbake

dev -&amp;amp;gt; site : Vérifier portfolio
activate site
site --&amp;amp;gt; dev : Projet absent de la liste publique
deactivate site
@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect3&amp;quot;&amp;gt;
&amp;lt;h4 id=&amp;quot;_可能な状態&amp;quot;&amp;gt;可能な状態&amp;lt;/h4&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
skinparam backgroundColor #FEFEFE

[*] --&amp;amp;gt; Draft : Création initiale
Draft --&amp;amp;gt; Published : Validation et publication
Published --&amp;amp;gt; Draft : Retrait temporaire
Draft --&amp;amp;gt; Archived : Projet abandonné
Published --&amp;amp;gt; Archived : Projet obsolète
Archived --&amp;amp;gt; [*] : Suppression définitive
Published --&amp;amp;gt; Published : Mises à jour

note right of Draft
  :jbake-status: draft
  Non visible publiquement
  Utile pour projets en cours
end note

note right of Published
  :jbake-status: published
  Visible sur le portfolio
  Indexé par JBake
end note

note right of Archived
  Déplacé dans archive/
  ou jbake-status: archived
  Non publié mais conservé
end note
@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect3&amp;quot;&amp;gt;
&amp;lt;h4 id=&amp;quot;_典型的な使用例&amp;quot;&amp;gt;典型的な使用例&amp;lt;/h4&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;作成中のプロジェクト&amp;lt;/strong&amp;gt; : ドラフトで作成し、準備ができたら公開する&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;Projet confidentiel temporairement&amp;lt;/strong&amp;gt; : 顧客の合意が得られるまでドラフト状態に保つ&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;主要アップデート&amp;lt;/strong&amp;gt; : ドラフトに切り替え、編集し、再公開&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;A/B testing&amp;lt;/strong&amp;gt; : 下書きで複製し、テストし、最良のバージョンを公開する&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_テンプレーティングアーキテクチャ&amp;quot;&amp;gt;テンプレーティングアーキテクチャ&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_再利用可能なテンプレートの戦略&amp;quot;&amp;gt;再利用可能なテンプレートの戦略&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
skinparam backgroundColor #FEFEFE
skinparam componentStyle rectangle

package &amp;quot;Thymeleaf テンプレート&amp;quot; {
  component [index.html] as index
  component [portfolio.html] as portfolio
  component [project.html] as project

  package &amp;quot;部分&amp;quot; {
    component [header.html] as header
    component [footer.html] as footer
    component [project-card.html] as card
    component [tech-badge.html] as badge
    component [gallery.html] as gallery
  }
}

package &amp;quot;JBakeデータ&amp;quot; {
  database &amp;quot;公開済みプロジェクト&amp;quot; as data
  database &amp;quot;コンテンツ (プロジェクト)&amp;quot; as content
}

index --&amp;amp;gt; header
index --&amp;amp;gt; footer

portfolio --&amp;amp;gt; header
portfolio --&amp;amp;gt; footer
portfolio --&amp;amp;gt; card
data --&amp;amp;gt; portfolio : itération

project --&amp;amp;gt; header
project --&amp;amp;gt; footer
project --&amp;amp;gt; badge
project --&amp;amp;gt; gallery
content --&amp;amp;gt; project : projet individuel

note right of card
  Fragment réutilisable
  pour afficher une carte
  de projet avec :
  - thumbnail
  - titre
  - tags
  - highlights
end note
@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_データ抽出パターン&amp;quot;&amp;gt;データ抽出パターン&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;JBakeは、AsciiDocの属性をThymeleafでアクセス可能なプロパティに自動的に変換します。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
skinparam backgroundColor #FEFEFE

rectangle &amp;quot;ドキュメント AsciiDoc&amp;quot; {
  (&amp;quot;:project-client: アクメ株式会社&amp;quot;) as attr1
  (&amp;quot;:project-duration: 6か月&amp;quot;) as attr2
  (&amp;quot;:project-tags: java, リアクト&amp;quot;) as attr3
}

rectangle &amp;quot;JBake モデル&amp;quot; {
  (content[&amp;#39;project-client&amp;#39;]) as prop1
  (content[&amp;#39;project-duration&amp;#39;]) as prop2
  (content.tags) as prop3
}

rectangle &amp;quot;テンプレート Thymeleaf&amp;quot; {
  (th:text=&amp;quot;${project[&amp;#39;project-client&amp;#39;]}&amp;quot;) as tmpl1
  (th:text=&amp;quot;${project[&amp;#39;project-duration&amp;#39;]}&amp;quot;) as tmpl2
  (th:each=&amp;quot;タグ : ${project.tags}&amp;quot;) as tmpl3
}

attr1 --&amp;amp;gt; prop1 : parsing
attr2 --&amp;amp;gt; prop2 : parsing
attr3 --&amp;amp;gt; prop3 : parsing

prop1 --&amp;amp;gt; tmpl1 : binding
prop2 --&amp;amp;gt; tmpl2 : binding
prop3 --&amp;amp;gt; tmpl3 : binding
@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_命名規則&amp;quot;&amp;gt;命名規則&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;プロジェクト属性&amp;lt;/strong&amp;gt; : プレフィックス`project-*` (ex: &amp;lt;code&amp;gt;project-client&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;project-tech-stack&amp;lt;/code&amp;gt;)&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;ファイル&amp;lt;/strong&amp;gt; : kebab-case (例:`ecommerce-platform.adoc`)&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;Images&amp;lt;/strong&amp;gt; : プロジェクト名プレフィックス（例：&amp;lt;code&amp;gt;ecommerce-platform-thumb.jpg&amp;lt;/code&amp;gt;)&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;テンプレート&amp;lt;/strong&amp;gt; : 機能的な名前 (例:`project-card.html`, &amp;lt;code&amp;gt;tech-badge.html&amp;lt;/code&amp;gt;）&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_公開ワークフロー&amp;quot;&amp;gt;公開ワークフロー&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_開発パイプライン&amp;quot;&amp;gt;開発パイプライン&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
skinparam backgroundColor #FEFEFE
skinparam handwritten false

class ProjetAsciiDoc {
  +titre: String
  +jbake-type: &amp;quot;プロジェクト&amp;quot;
  +jbake-status: published|draft
  +jbake-date: Date
  +jbake-tags: List&amp;amp;lt;String&amp;amp;gt;
  __
  +project-category: String
  +project-client: String
  +project-duration: String
  +project-role: String
  +project-thumbnail: String
  +project-gallery: List&amp;amp;lt;String&amp;amp;gt;
  +project-tech-stack: String
  +project-highlights: List&amp;amp;lt;String&amp;amp;gt;
  +project-demo-url: String
  +project-github-url: String
  __
  +body: HTML (converti)
}

class JBakeEngine {
  +parse(asciidoc)
  +extractMetadata()
  +convertToHTML()
}

class ThymeleafTemplate {
  +portfolio.html
  +project.html
  +partials/project-card.html
}

class PortfolioPage {
  +published_projects: List
  +filtres: categories
}

ProjetAsciiDoc --&amp;amp;gt; JBakeEngine : parse
JBakeEngine --&amp;amp;gt; ThymeleafTemplate : fournit données
ThymeleafTemplate --&amp;amp;gt; PortfolioPage : génère
@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_環境&amp;quot;&amp;gt;環境&amp;lt;/h3&amp;gt;
&amp;lt;table class=&amp;quot;tableblock frame-all grid-all stretch&amp;quot;&amp;gt;
&amp;lt;colgroup&amp;gt;
&amp;lt;col style=&amp;quot;width: 20%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 40%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 40%;&amp;quot;&amp;gt;
&amp;lt;/colgroup&amp;gt;
&amp;lt;thead&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;th class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;環境&amp;lt;/th&amp;gt;
&amp;lt;th class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;使用&amp;lt;/th&amp;gt;
&amp;lt;th class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;受け入れられたステータス&amp;lt;/th&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/thead&amp;gt;
&amp;lt;tbody&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;ローカル&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;開発とプレビュー&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;下書き, 公開済み&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;ステージング&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;本番前検証&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;publishedのみ&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;生産&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;公共サイト&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;公開済みのみ&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/tbody&amp;gt;
&amp;lt;/table&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_拡張性&amp;quot;&amp;gt;拡張性&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_新しい属性の追加&amp;quot;&amp;gt;新しい属性の追加&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;データモデルを充実させるには、単純にプレフィックス付きの新しい属性を追加`project-*`:&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;`project-awards`賞と表彰&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;code&amp;gt;project-testimonial&amp;lt;/code&amp;gt;: クライアント見積もり&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;code&amp;gt;project-team-size&amp;lt;/code&amp;gt;: チームサイズ&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;code&amp;gt;project-budget-range&amp;lt;/code&amp;gt;: 予算範囲&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;これらの属性は、JBakeエンジンを変更せずにテンプレート内で自動的に利用可能になります。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_高度な分類&amp;quot;&amp;gt;高度な分類&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
skinparam backgroundColor #FEFEFE

object Projet {
  project-category = &amp;quot;ウェブ&amp;quot;
  project-subcategory = &amp;quot;電子商取引&amp;quot;
  project-industry = &amp;quot;小売り&amp;quot;
  project-complexity = &amp;quot;高い&amp;quot;
}

object Taxonomie {
  categories : [web, mobile, data, devops]
  subcategories : Map&amp;amp;lt;category, List&amp;amp;gt;
  industries : [retail, finance, healthcare, ...]
  complexities : [low, medium, high]
}

Projet --&amp;amp;gt; Taxonomie : classifié selon

note right of Taxonomie
  Permet filtrage multi-critères
  dans le template portfolio.html
  via JavaScript ou côté serveur
end note
@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_ベストプラクティス&amp;quot;&amp;gt;ベストプラクティス&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_ファイルの整理&amp;quot;&amp;gt;ファイルの整理&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;1 ファイル = 1 プロジェクト&amp;lt;/strong&amp;gt; : 複数のプロジェクトを混ぜないでください&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;専用フォルダ内の画像&amp;lt;/strong&amp;gt;&amp;lt;code&amp;gt;assets/img/portfolio/nom-projet/&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;一貫した命名規則&amp;lt;/strong&amp;gt; : 検索と保守を容易にする&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;Versioning Git&amp;lt;/strong&amp;gt; : 変更の完全な追跡&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_コンテンツ管理&amp;quot;&amp;gt;コンテンツ管理&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;デフォルトの下書きステータス&amp;lt;/strong&amp;gt; : 公開するのは準備ができたときだけ&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;公開前レビュー&amp;lt;/strong&amp;gt; : 品質と機密性の確認&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;完全なメタデータ&amp;lt;/strong&amp;gt; : すべての関連フィールドを入力してください&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;豊かなナラティブコンテンツ&amp;lt;/strong&amp;gt; : メタデータに限定しない&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_パフォーマンス&amp;quot;&amp;gt;パフォーマンス&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;画像を最適化&amp;lt;/strong&amp;gt; : コミット前の圧縮&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;必要に応じたページネーション&amp;lt;/strong&amp;gt; : 20プロジェクト以上の場合&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;Lazy loading&amp;lt;/strong&amp;gt; : ギャラリーの画像は必要に応じて読み込まれます&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;ブラウザキャッシュ&amp;lt;/strong&amp;gt; : アセット用の適切なヘッダー&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_結論&amp;quot;&amp;gt;結論&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;このアーキテクチャは次のことを許可します :&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;使いやすさ&amp;lt;/strong&amp;gt; : プロジェクトを追加 = テキストファイルを作成&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;柔軟性&amp;lt;/strong&amp;gt; : 新しい属性を通じて拡張可能&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;保守性&amp;lt;/strong&amp;gt; : コンテンツとプレゼンテーションの分離&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;トレーサビリティ&amp;lt;/strong&amp;gt; : Gitの完全なバージョン管理&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;自動化&amp;lt;/strong&amp;gt; : ビルドとデプロイの継続的な可能性&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;AsciiDocの選択は、サイトの他の部分との一貫性を保ちながら、プロフェッショナルなポートフォリオに必要なメタデータの豊かさを提供します。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;</description>
        </item><item>
            <title>ハイブリッドアーキテクチャ : SupabaseとSpring Bootによる両方の世界のベスト</title>
            <link >https://cheroliv.com/blog/pilot-batch/0100_jbake_supabase_springboot_hybride_post.html</link>
            <pubDate>Wed, 14 Jan 2026 00:00:00 +0000</pubDate>
            <guid isPermaLink="false">blog/pilot-batch/0100_jbake_supabase_springboot_hybride_post.html</guid>
            <description>&amp;lt;div id=&amp;quot;preamble&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;読了時間 : 12 minutes&amp;lt;/div&amp;gt;
&amp;lt;p&amp;gt;SupabaseのシンプルさとSpring Bootのパワーの間で選択するのではなく、両方を組み合わせてみませんか？それぞれの技術の長所を活かしたハイブリッドアーキテクチャをご紹介します。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;dlist&amp;quot;&amp;gt;
&amp;lt;dl&amp;gt;
&amp;lt;dt class=&amp;quot;hdlist1&amp;quot;&amp;gt;強迫性障害&amp;lt;/dt&amp;gt;
&amp;lt;dd&amp;gt;
&amp;lt;p&amp;gt;[]&amp;lt;/p&amp;gt;
&amp;lt;/dd&amp;gt;
&amp;lt;/dl&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_現代建築の偽りのジレンマ&amp;quot;&amp;gt;現代建築の偽りのジレンマ&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;静的フロントエンドを使ってモダンなアプリケーションを構築するとき、しばしば二者択一の選択に直面することになります：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;Backend-as-a-Serviceのソリューションにすべてを賭ける。&amp;lt;/strong&amp;gt;(Supabase, Firebase) - シンプルだが制限がある&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;完全なバックエンドを構築する&amp;lt;/strong&amp;gt;(Spring Boot, Node.js) - 強力だが複雑&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;この選択は誤った二択です。ハイブリッドアーキテクチャは第三の道を提案します： &amp;lt;strong&amp;gt;各テクノロジーが得意とする場所で使用する&amp;lt;/strong&amp;gt;。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_建築ビジョン&amp;quot;&amp;gt;建�築ビジョン&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_伝統的なアーキテクチャ_モノリシック&amp;quot;&amp;gt;伝統的なアーキテクチャ: モノリシック&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
skinparam backgroundColor #FEFEFE
skinparam componentStyle rectangle

package &amp;quot;伝統的建築&amp;quot; {
  actor Utilisateur as user
  component &amp;quot;フロントエンド&amp;quot; as frontend #LightBlue
  component &amp;quot;モノリシックバックエンド&amp;quot; as backend #LightCoral {
    [Authentification]
    [CRUD]
    [Logique Métier]
    [Jobs]
    [APIs Tierces]
  }
  database &amp;quot;データベース&amp;quot; as db #LightGray

  user --&amp;amp;gt; frontend
  frontend --&amp;amp;gt; backend : Toutes les requêtes
  backend --&amp;amp;gt; db
}

note right of backend
  Tout passe par le backend
  même les opérations simples

  ⚠️ Point de congestion unique
  ⚠️ Complexité dès le départ
  ⚠️ Couplage fort
end note
@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;このアプローチでは、最も単純な操作（記事の読み込み、コメントの作成）であっても、すべてバックエンドを経由する必要があります。最初の日から複雑さのコストを支払うことになります。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_baasアーキテクチャ全代表者&amp;quot;&amp;gt;BaaSアーキテクチャ：全代表者&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
skinparam backgroundColor #FEFEFE
skinparam componentStyle rectangle

package &amp;quot;アーキテクチャ BaaS ピュア&amp;quot; {
  actor Utilisateur as user
  component &amp;quot;フロントエンド&amp;quot; as frontend #LightBlue
  cloud &amp;quot;Supabase / Firebase&amp;quot; as baas #LightGreen {
    [Auth]
    [Database]
    [Storage]
    [Edge Functions]
  }

  user --&amp;amp;gt; frontend
  frontend --&amp;amp;gt; baas : Toutes les opérations
}

note right of baas
  Développement rapide
  Pas de serveur à gérer

  ⚠️ Limité pour logique complexe
  ⚠️ Vendor lock-in
  ⚠️ Edge Functions contraintes
end note
@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;逆に、すべてをBaaSに委ねるのは最初は魅力的ですが、ビジネスロジックが複雑になるとすぐに限界が露呈します。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_ハイブリッドアーキテクチャ_責任の分離&amp;quot;&amp;gt;ハイブリッドアーキテクチャ: 責任の分離&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
skinparam backgroundColor #FEFEFE
skinparam componentStyle rectangle

actor Utilisateur as user #LightBlue

package &amp;quot;フロントエンド層&amp;quot; {
  component &amp;quot;JBakeの静的サイト&amp;quot; as frontend #SkyBlue
}

package &amp;quot;シンプルな層 (Supabase)&amp;quot; #LightGreen {
  component &amp;quot;認証&amp;quot; as auth
  component &amp;quot;CRUD基本&amp;quot; as crud
  component &amp;quot;ファイル ストレージ&amp;quot; as storage
  component &amp;quot;リアルタイム&amp;quot; as realtime
}

package &amp;quot;ビジネスレイヤー (Spring Boot)&amp;quot; #Coral {
  component &amp;quot;複雑なロジック&amp;quot; as logic
  component &amp;quot;オーケストレーション&amp;quot; as orchestration
  component &amp;quot;計画されたジョブ&amp;quot; as jobs
  component &amp;quot;統合&amp;quot; as integrations
}

database &amp;quot;PostgreSQL 共有&amp;quot; as db #LightGray

user --&amp;amp;gt; frontend

frontend --&amp;amp;gt; auth : OAuth2, JWT
frontend --&amp;amp;gt; crud : Articles, Profils
frontend --&amp;amp;gt; storage : Images, Fichiers
frontend --&amp;amp;gt; realtime : Notifications

frontend --&amp;amp;gt; logic : Calculs, Rapports
frontend --&amp;amp;gt; orchestration : Workflows
logic --&amp;amp;gt; integrations : Stripe, APIs
orchestration --&amp;amp;gt; db
jobs --&amp;amp;gt; db

crud --&amp;amp;gt; db
auth --&amp;amp;gt; db

note bottom of db
  **Une seule source de vérité**
  Partagée entre Supabase et Spring Boot
end note

note right of auth
  **Gratuit jusqu&amp;#39;à 50k users**
  Configuration en quelques clics
  OAuth2 multi-providers
end note

note right of logic
  **Activé seulement si nécessaire**
  Kotlin + Coroutines
  Transactions complexes
end note
@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;ハイブリッドアーキテクチャは、複雑さと操作の性質に応じて、責任をはっきりと分離します。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_設計原則&amp;quot;&amp;gt;設計原則&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_原則1シンプルに始め賢く進化させる&amp;quot;&amp;gt;原則1：シンプルに始め、賢く進化させる&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
skinparam backgroundColor #FEFEFE

rectangle &amp;quot;フェーズ 1 : MVP&amp;quot; #LightGreen {
  component &amp;quot;JBake + Supabase&amp;quot; as mvp
  note right
    ✓ Développement en jours
    ✓ Coût : 0€
    ✓ Validation concept
  end note
}

rectangle &amp;quot;**フェーズ 2: 成長**&amp;quot; #LightYellow {
  component &amp;quot;JBake + Supabase
+ Spring Boot (オプション)&amp;quot; as growth
  note right
    ✓ Logique métier émerge
    ✓ Premiers jobs planifiés
    ✓ Intégrations tierces
  end note
}

rectangle &amp;quot;フェーズ 3 : スケール&amp;quot; #LightCoral {
  component &amp;quot;完全なアーキテクチャ&amp;quot; as scale
  note right
    ✓ Orchestration complexe
    ✓ Performances optimisées
    ✓ Cache distribué
  end note
}

mvp -down-&amp;amp;gt; growth : Quand la complexité\nle justifie
growth -down-&amp;amp;gt; scale : Optimisation\ncontinue
@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;必要でなければ、Spring Bootを構築しないでください。&amp;lt;/strong&amp;gt;Supabaseで始めて、複雑さが必要とされるときにSpring Bootを追加してください。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_原則2_操作の性質による分離&amp;quot;&amp;gt;原則2 : 操作の性質による分離&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startmindmap
skinparam backgroundColor #FEFEFE
* Opérations\nApplicatives

left side

** Opérations Simples\n(Supabase)
***_ CRUD Standard
****_ Lecture
****_ Création
****_ Mise à jour
****_ Suppression
***_ Authentification
****_ Login/Logout
****_ OAuth2
****_ Gestion session
***_ Stockage
****_ Upload fichiers
****_ CDN automatique
***_ Temps Réel
****_ WebSocket
****_ Notifications

right side

** Opérations Complexes\n(Spring Boot)
***_ Logique Métier
****_ Calculs complexes
****_ Règles métier
****_ Validations avancées
***_ Orchestration
****_ Multi-services
****_ Transactions distribuées
****_ Saga patterns
***_ Tâches Planifiées
****_ Rapports périodiques
****_ Synchronisations
****_ Nettoyages
***_ Intégrations
****_ Paiements (Stripe)
****_ APIs tierces
****_ Services ML/AI

@endmindmap&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_原則_3_単一の真実の源&amp;quot;&amp;gt;原則 3 : 単一の真実の源&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
skinparam backgroundColor #FEFEFE

database &amp;quot;ポストグレスQL&amp;quot; as db #LightGray {
  package &amp;quot;スキーマ: auth (Supabase)&amp;quot; #LightGreen {
    [users]
    [sessions]
    [identities]
  }

  package &amp;quot;スキーマ: 公開 (共有)&amp;quot; #SkyBlue {
    [articles]
    [comments]
    [profiles]
  }

  package &amp;quot;スキーマ: ビジネス (Spring Boot)&amp;quot; #Coral {
    [orders]
    [payments]
    [reports]
  }
}

component &amp;quot;Supabase&amp;quot; as supabase #LightGreen
component &amp;quot;スプリングブート&amp;quot; as spring #Coral

supabase -down-&amp;amp;gt; users : Gère
supabase -down-&amp;amp;gt; sessions : Gère
supabase -down-&amp;amp;gt; articles : Accède
supabase -down-&amp;amp;gt; comments : Accède
supabase -down-&amp;amp;gt; profiles : Accède

spring -down-&amp;amp;gt; articles : Accède
spring -down-&amp;amp;gt; profiles : Accède
spring -down-&amp;amp;gt; orders : Gère
spring -down-&amp;amp;gt; payments : Gère
spring -down-&amp;amp;gt; reports : Gère

note right of db
  **Avantages :**
  • Pas de synchronisation complexe
  • JOINs possibles entre tables
  • Cohérence garantie
  • Migrations unifiées
end note
@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;同じPostgreSQLインスタンスを共有することで、SupabaseとSpring Bootは複雑な同期なしに同じデータを扱います。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_フローのオーケストレーション&amp;quot;&amp;gt;フローのオーケストレーション&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_フラックス_1_中央認証&amp;quot;&amp;gt;フラックス 1: 中央認証&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
skinparam backgroundColor #FEFEFE
autonumber

actor &amp;quot;ユーザー&amp;quot; as user
participant &amp;quot;JBake&amp;quot; as jbake
participant &amp;quot;Supabase認証&amp;quot; as auth
participant &amp;quot;Spring Boot&amp;quot; as spring
database &amp;quot;PostgreSQL&amp;quot; as db

== Authentification ==
user -&amp;amp;gt; jbake : Clique &amp;quot;ログイン&amp;quot;
jbake -&amp;amp;gt; auth : Redirect OAuth2 (Google/GitHub)
auth -&amp;amp;gt; user : Consent screen
user -&amp;amp;gt; auth : Autorise
auth -&amp;amp;gt; auth : Génère JWT
auth -&amp;amp;gt; jbake : Retourne JWT + Refresh Token
jbake -&amp;amp;gt; jbake : Stocke tokens (sessionStorage)

== Accès aux Ressources ==
group Opération Simple (CRUD)
  user -&amp;amp;gt; jbake : Crée un article
  jbake -&amp;amp;gt; db : POST avec JWT
  note right: Supabase Row Level Security\nvérifie le JWT automatiquement
  db -&amp;amp;gt; jbake : Article créé
end

group Opération Complexe (Métier)
  user -&amp;amp;gt; jbake : Génère un rapport
  jbake -&amp;amp;gt; spring : POST /api/reports\navec JWT
  spring -&amp;amp;gt; spring : Valide JWT Supabase
  spring -&amp;amp;gt; spring : Extrait claims (user_id, roles)
  spring -&amp;amp;gt; db : Requêtes complexes
  spring -&amp;amp;gt; jbake : Rapport généré
end

note over auth, spring
  **Le JWT est universel**
  Valide par Supabase ET Spring Boot
  Pas de double authentification
end note
@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;重要なポイント&amp;lt;/strong&amp;gt;一つの認証プロセス、一つのJWT、どこでも使える。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_フラックス_2_ビジネスプロセスの複雑なオーケストレーション&amp;quot;&amp;gt;フラックス 2 : ビジネスプロセスの複雑なオーケストレーション&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
skinparam backgroundColor #FEFEFE
autonumber

actor &amp;quot;クライアント&amp;quot; as user
participant &amp;quot;JBake&amp;quot; as jbake
participant &amp;quot;スプリングブート&amp;quot; as spring
participant &amp;quot;Supabase データベース&amp;quot; as supadb
participant &amp;quot;Stripe API&amp;quot; as stripe
participant &amp;quot;在庫サービス&amp;quot; as inventory
participant &amp;quot;メールサービス&amp;quot; as email
database &amp;quot;PostgreSQL&amp;quot; as db

user -&amp;amp;gt; jbake : Passe commande
jbake -&amp;amp;gt; spring : POST /api/orders/create

== Orchestration Spring Boot ==
spring -&amp;amp;gt; db : BEGIN TRANSACTION

par Vérifications Parallèles
  spring -&amp;amp;gt; inventory : Vérifier stock
  inventory -&amp;amp;gt; spring : Stock OK
else
  spring -&amp;amp;gt; db : Vérifier profil client
  db -&amp;amp;gt; spring : Client vérifié
end

spring -&amp;amp;gt; stripe : Créer Payment Intent
stripe -&amp;amp;gt; spring : Intent créé (ID: pi_xxx)

spring -&amp;amp;gt; db : Créer Order (status: PENDING)
db -&amp;amp;gt; spring : Order créé

spring -&amp;amp;gt; stripe : Confirmer paiement
stripe -&amp;amp;gt; spring : Paiement confirmé

spring -&amp;amp;gt; db : Update Order (status: PAID)
spring -&amp;amp;gt; inventory : Décrémenter stock
spring -&amp;amp;gt; db : COMMIT TRANSACTION

par Notifications Asynchrones
  spring -&amp;amp;gt; email : Email confirmation
else
  spring -&amp;amp;gt; supadb : Insert notification
  note right: Notification temps réel\nvia Supabase Realtime
end

spring -&amp;amp;gt; jbake : Order confirmé
jbake -&amp;amp;gt; user : Affiche confirmation

note over spring
  **Responsabilités Spring Boot :**
  • Transaction ACID
  • Orchestration multi-services
  • Rollback automatique si erreur
  • Gestion des cas limites
end note
@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;Spring Bootがもたらすもの&amp;lt;/strong&amp;gt;: 信頼性の高い複数のシステムに関わる複雑なプロセスのオーケストレーション、トランザクション保証付き。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_フラックス_3_予定されたジョブと同期&amp;quot;&amp;gt;フラックス 3 : 予定されたジョブと同期&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
skinparam backgroundColor #FEFEFE

participant &amp;quot;スケジューラ
(Spring Boot)&amp;quot; as scheduler
participant &amp;quot;レポートサービス&amp;quot; as report
participant &amp;quot;PostgreSQL&amp;quot; as db
participant &amp;quot;外部 API&amp;quot; as api
participant &amp;quot;メールサービス&amp;quot; as email
participant &amp;quot;Supabase ストレージ&amp;quot; as storage

== Job Quotidien : 2h00 ==
activate scheduler
scheduler -&amp;amp;gt; report : Déclenche génération rapport

activate report
report -&amp;amp;gt; db : Récupère données\ndes dernières 24h
db -&amp;amp;gt; report : Dataset

report -&amp;amp;gt; report : Calculs &amp;amp;amp; Agrégations
report -&amp;amp;gt; report : Génération PDF

report -&amp;amp;gt; storage : Upload PDF
storage -&amp;amp;gt; report : URL publique

report -&amp;amp;gt; email : Envoie aux admins\navec lien PDF
deactivate report

== Job Hebdomadaire : Dimanche 3h00 ==
scheduler -&amp;amp;gt; report : Synchronisation externe

activate report
report -&amp;amp;gt; api : Fetch données externes
api -&amp;amp;gt; report : Nouvelles données

report -&amp;amp;gt; db : Mise à jour tables
report -&amp;amp;gt; db : Nettoyage données obsolètes
deactivate report

== Job Mensuel : 1er du mois ==
scheduler -&amp;amp;gt; report : Facturation

activate report
report -&amp;amp;gt; db : Liste clients actifs
report -&amp;amp;gt; report : Calcul montants
report -&amp;amp;gt; api : Génération factures (Stripe)
report -&amp;amp;gt; email : Envoi factures
deactivate report

deactivate scheduler

note right of scheduler
  **Impossible avec Supabase seul**
  Edge Functions non adaptées
  pour jobs longs et récurrents
end note
@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;Spring Bootがもたらすもの&amp;lt;/strong&amp;gt;: 状態管理、自動リトライ、および保証された実行を備えた信頼性の高いスケジュールされたジョブ&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_意思決定マトリクス&amp;quot;&amp;gt;意思決定マトリクス&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_supabaseを使うべき時は&amp;quot;&amp;gt;Supabaseを使うべき時は？&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
skinparam backgroundColor #FEFEFE

start

:Nouvelle fonctionnalité à implémenter;

if (CRUD simple ?) then (oui)
  :✅ **Supabase**;
  stop
else (non)
  if (Authentification ?) then (oui)
    :✅ **Supabase Auth**;
    stop
  else (non)
    if (Upload fichiers ?) then (oui)
      :✅ **Supabase Storage**;
      stop
    else (non)
      if (Temps réel ?) then (oui)
        :✅ **Supabase Realtime**;
        stop
      else (non)
        if (Row Level Security\nsuffisante ?) then (oui)
          :✅ **Supabase + Policies**;
          stop
        else (non)
          :⚠️ **Considérer Spring Boot**;
          #Coral:Passer à l&amp;#39;arbre\nde décision Spring Boot;
          stop
        endif
      endif
    endif
  endif
endif

@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_spring_bootを使うべき時は&amp;quot;&amp;gt;Spring Bootを使うべき時は？&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
skinparam backgroundColor #FEFEFE

start

:Nouvelle fonctionnalité complexe;

if (Orchestration\nmulti-services ?) then (oui)
  :✅ **Spring Boot**;
  stop
else (non)
  if (Transaction ACID\ncritique ?) then (oui)
    :✅ **Spring Boot**;
    stop
  else (non)
    if (Job planifié ?) then (oui)
      :✅ **Spring Boot Scheduler**;
      stop
    else (non)
      if (Intégration API\ntierce complexe ?) then (oui)
        :✅ **Spring Boot**;
        stop
      else (non)
        if (Calculs lourds\n&amp;amp;gt; 10 secondes ?) then (oui)
          :✅ **Spring Boot**;
          stop
        else (non)
          if (Cache distribué\nnécessaire ?) then (oui)
            :✅ **Spring Boot + Redis**;
            stop
          else (non)
            :⚠️ **Probablement Supabase**;
            #LightGreen:Revenir à l&amp;#39;arbre\nde décision Supabase;
            stop
          endif
        endif
      endif
    endif
  endif
endif

@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_プロジェクトタイプ別の建築例&amp;quot;&amp;gt;プロジェクトタイプ別の建築例&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_ブログ_ポートフォリオ&amp;quot;&amp;gt;ブログ / ポートフォリオ&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
skinparam backgroundColor #FEFEFE
skinparam componentStyle rectangle

package &amp;quot;個人ブログ - 95% Supabase&amp;quot; {
  component &amp;quot;JBake&amp;quot; as jbake #SkyBlue

  package &amp;quot;Supabase (無料)&amp;quot; #LightGreen {
    [Auth: OAuth2 Google]
    [Articles (CRUD)]
    [Commentaires]
    [Images (Storage)]
    [Notifications Realtime]
  }

  package &amp;quot;Spring Boot (オプション)&amp;quot; #LightCoral {
    [Newsletter Mensuelle]
    note bottom: Job planifié uniquement
  }

  database &amp;quot;PostgreSQL&amp;quot; as db

  jbake --&amp;amp;gt; [Auth: OAuth2 Google]
  jbake --&amp;amp;gt; [Articles (CRUD)]
  jbake --&amp;amp;gt; [Commentaires]
  jbake --&amp;amp;gt; [Images (Storage)]
  jbake --&amp;amp;gt; [Notifications Realtime]

  [Articles (CRUD)] --&amp;amp;gt; db
  [Commentaires] --&amp;amp;gt; db
  [Newsletter Mensuelle] --&amp;amp;gt; db
}

note bottom of &amp;quot;Spring Boot (オプション)&amp;quot;
  **Spring Boot pas obligatoire**
  Newsletter peut être gérée
  par un service tiers (Mailchimp)
end note
@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;評決&amp;lt;/strong&amp;gt;: 100% Supabaseは十分すぎるほどです。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_saas_アプリケーション&amp;quot;&amp;gt;SaaS アプリケーション&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
skinparam backgroundColor #FEFEFE
skinparam componentStyle rectangle

package &amp;quot;アプリケーション SaaS - ハイブリッド アーキテクチャ&amp;quot; {
  component &amp;quot;JBake / React&amp;quot; as frontend #SkyBlue

  package &amp;quot;Supabase&amp;quot; #LightGreen {
    [Auth Multi-tenant]
    [Profils Utilisateurs]
    [Données Simples]
    [Storage Documents]
  }

  package &amp;quot;スプリング ブート&amp;quot; #Coral {
    [Facturation (Stripe)]
    [Analytics Avancées]
    [Rapports Mensuels]
    [Quotas &amp;amp;amp; Limites]
    [Webhooks Stripe]
  }

  cloud &amp;quot;外部サービス&amp;quot; {
    [Stripe API]
    [SendGrid Email]
  }

  database &amp;quot;PostgreSQL 共有&amp;quot; as db

  frontend --&amp;amp;gt; [Auth Multi-tenant]
  frontend --&amp;amp;gt; [Profils Utilisateurs]
  frontend --&amp;amp;gt; [Données Simples]
  frontend --&amp;amp;gt; [Facturation (Stripe)]
  frontend --&amp;amp;gt; [Analytics Avancées]

  [Auth Multi-tenant] --&amp;amp;gt; db
  [Profils Utilisateurs] --&amp;amp;gt; db
  [Données Simples] --&amp;amp;gt; db

  [Facturation (Stripe)] --&amp;amp;gt; db
  [Facturation (Stripe)] --&amp;amp;gt; [Stripe API]
  [Analytics Avancées] --&amp;amp;gt; db
  [Rapports Mensuels] --&amp;amp;gt; db
  [Rapports Mensuels] --&amp;amp;gt; [SendGrid Email]
  [Webhooks Stripe] ..&amp;amp;gt; [Stripe API] : Écoute
}

note right of &amp;quot;スプリング ブート&amp;quot;
  **Nécessaire pour :**
  • Gestion abonnements
  • Facturation récurrente
  • Quotas dynamiques
  • Analytics complexes
  • Webhooks fiables
end note
@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;判決&amp;lt;/strong&amp;gt;: ハイブリッドアーキテクチャが必要です。Supabase は基本部分に、Spring Boot はクリティカルな部分（支払い、請求）に使用します。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_eコマース&amp;quot;&amp;gt;Eコマース&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
skinparam backgroundColor #FEFEFE
skinparam componentStyle rectangle

package &amp;quot;Eコマース - 70% Spring Boot&amp;quot; {
  component &amp;quot;ストアフロント(JBake/React)&amp;quot; as frontend #SkyBlue

  package &amp;quot;Supabase&amp;quot; #LightGreen {
    [Auth Clients]
    [Catalogue Produits\n(lecture seule)]
    [Images Produits]
  }

  package &amp;quot;Spring Boot (コアビジネス)&amp;quot; #Coral {
    [Gestion Commandes]
    [Paiements Stripe]
    [Gestion Stock]
    [Calcul Frais Port]
    [Génération Factures]
    [Synchronisation ERP]
    [Emails Transactionnels]
  }

  cloud &amp;quot;統合&amp;quot; {
    [Stripe]
    [Transporteur API]
    [ERP Externe]
  }

  database &amp;quot;PostgreSQL&amp;quot; as db

  frontend --&amp;amp;gt; [Auth Clients]
  frontend --&amp;amp;gt; [Catalogue Produits\n(lecture seule)]
  frontend --&amp;amp;gt; [Gestion Commandes]

  [Auth Clients] --&amp;amp;gt; db
  [Catalogue Produits\n(lecture seule)] --&amp;amp;gt; db

  [Gestion Commandes] --&amp;amp;gt; db
  [Paiements Stripe] --&amp;amp;gt; [Stripe]
  [Gestion Stock] --&amp;amp;gt; db
  [Calcul Frais Port] --&amp;amp;gt; [Transporteur API]
  [Génération Factures] --&amp;amp;gt; db
  [Synchronisation ERP] --&amp;amp;gt; [ERP Externe]
  [Synchronisation ERP] --&amp;amp;gt; db
}

note right of &amp;quot;Spring Boot (コアビジネス)&amp;quot;
  **Spring Boot indispensable :**
  • Transactions critiques
  • Orchestration complexe
  • Intégrations multiples
  • Conformité légale
  • Jobs de synchronisation
end note
@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;判決&amp;lt;/strong&amp;gt;Spring Bootは不可欠です。Supabaseは認証とカタログのみに使用します。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_段階的移行戦略&amp;quot;&amp;gt;段階的移行戦略&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
skinparam backgroundColor #FEFEFE

|Semaine 1-2|
start
:Créer projet Supabase;
:Configurer Auth (Google, GitHub);
:Définir schéma PostgreSQL initial;
:Implémenter CRUD de base sur JBake;
:Déployer MVP sur GitHub Pages;
note right
  **Livrable :** Application fonctionnelle
  **Coût :** 0€
  **Temps :** 1-2 semaines
end note

|Semaine 3-4|
:Observer utilisation réelle;
:Identifier limitations;

|Décision|
if (Logique complexe\némerge ?) then (non)
  |Supabase|
  :Continuer avec Supabase seul;
  :Ajouter Edge Functions si besoin;
  stop
else (oui)
  |Spring Boot|
  :Créer projet Spring Boot;
  :Configurer validation JWT Supabase;
  :Migrer logique complexe vers Spring Boot;
  note right
    **Migration sélective**
    Seulement ce qui est complexe
  end note
endif

|Semaines suivantes|
:Déployer Spring Boot (Cloud Run, EC2);
:Connecter à PostgreSQL Supabase;
:Implémenter premiers jobs planifiés;
:Intégrer APIs tierces;

stop

note right
  **Architecture finale hybride**
  Supabase + Spring Boot
  en parfaite harmonie
end note
@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_コストと運営上の考慮事項&amp;quot;&amp;gt;コストと運営上の考慮事項&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_コスト構造&amp;quot;&amp;gt;コスト構造&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
skinparam backgroundColor #FEFEFE

package &amp;quot;月次推定コスト&amp;quot; {

  rectangle &amp;quot;MVPフェーズ
(0-1000 ユーザー)&amp;quot; #LightGreen {
    [JBake (GitHub Pages): 0€]
    [Supabase: 0€]
    [Spring Boot: N/A]
    note bottom: **Total: 0€/mois**
  }

  rectangle &amp;quot;成長フェーズ
(1k-10k ユーザー)&amp;quot; #LightYellow {
    [JBake (GitHub Pages): 0€]
    [Supabase: 0€]
    [Spring Boot (Cloud Run): 20-50€]
    [PostgreSQL (si séparé): 0-30€]
    note bottom: **Total: 20-80€/mois**
  }

  rectangle &amp;quot;フェーズ スケール\n(10k-100k ユーザー)&amp;quot; #LightCoral {
    [JBake (Netlify Pro): 19€]
    [Supabase Pro: 25€]
    [Spring Boot (instances multiples): 100-300€]
    [Redis Cache: 20-50€]
    [Monitoring: 20€]
    note bottom: **Total: 184-414€/mois**
  }
}

note right of &amp;quot;フェーズ スケール\n(10k-100k ユーザー)&amp;quot;
  À ce stade, les revenus
  justifient largement les coûts
end note
@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_オペレーションの責任&amp;quot;&amp;gt;オペレーションの責任&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
skinparam backgroundColor #FEFEFE

package &amp;quot;誰が何を担当しているか?&amp;quot; {

  rectangle &amp;quot;Supabase によって管理されている (0 労力)&amp;quot; #LightGreen {
    [Authentification]
    [Base de données]
    [Backups automatiques]
    [Scaling automatique]
    [Monitoring DB]
    [Sécurité DB]
  }

  rectangle &amp;quot;GitHubによって管理されています（0の労力）&amp;quot; #SkyBlue {
    [Hébergement site statique]
    [HTTPS/SSL]
    [CDN global]
    [Déploiement automatique]
  }

  rectangle &amp;quot;Spring Boot を管理する&amp;quot; #LightCoral {
    [Déploiement application]
    [Monitoring APM]
    [Logs centralisés]
    [Scaling horizontal]
    [Mises à jour sécurité]
  }
}

note bottom of &amp;quot;Spring Boot を管理する&amp;quot;
  **Minimisable avec :**
  • Cloud Run (serverless)
  • Kubernetes (si nécessaire)
  • Services managés (RDS, etc.)
end note
@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_結論完璧なバランス&amp;quot;&amp;gt;結論：完璧なバランス&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;Supabase + Spring Bootのハイブリッドアーキテクチャは妥協ではなく、これは&amp;lt;strong&amp;gt;シナジー&amp;lt;/strong&amp;gt;.&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_覚えておくべき原則&amp;quot;&amp;gt;覚えておくべき原則&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startmindmap
skinparam backgroundColor #FEFEFE
* Architecture\nHybride

** Commencer Simple
***_ MVP avec Supabase
***_ 0€ de coût initial
***_ Validation rapide

** Évoluer Intelligemment
***_ Ajouter Spring Boot\nsi nécessaire
***_ Migration progressive
***_ Pas de refonte totale

** Exploiter les Forces
***_ Supabase: Simplicité
***_ Spring Boot: Puissance
***_ PostgreSQL: Source unique

** Minimiser la Complexité
***_ Pas de synchronisation
***_ Pas de duplication
***_ Architecture claire

** Optimiser les Coûts
***_ Gratuit au départ
***_ Scaling progressif
***_ ROI évident

@endmindmap&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_このアーキテクチャを選ぶのはいつですか&amp;quot;&amp;gt;このアーキテクチャを選ぶのはいつですか？&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;�✅ このアーキテクチャは理想的です、もし：&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;すぐに始めたい（MVPは日単位で、月単位ではない）&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;ビジネスの複雑さの増加を見越しています&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;初期コストを最小限に抑えたい&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;PostgreSQL が好きで、単一の真実のソースが欲しい&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;あなたはKotlinとコルーチンをビジネスコードのために気に入っています&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;あなたは完全なベンダーロックインを避けたい&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;�❌ このアーキテクチャは適していない場合：&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;あなたのプロジェクトはシンプルで、そのまま保たれます (個人ブログ → Supabase 100% で十分)&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;あなたは既にマスターしているバックエンドスタックを持っています。&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;あなたは伝統的なモノリスを好みます&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;.NET、Python、またはその他のバックエンド言語が必要です。&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_最終的な概観&amp;quot;&amp;gt;最終的な概観&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
skinparam backgroundColor #FEFEFE

package &amp;quot;完全なハイブリッドアーキテクチャ&amp;quot; {

  actor &amp;quot;ユーザー&amp;quot; as users

  rectangle &amp;quot;フロントエンド (静的)&amp;quot; #SkyBlue {
    [JBake / GitHub Pages]
    note right: Gratuit, CDN global
  }

  rectangle &amp;quot;シンプルバックエンド(Supabase)&amp;quot; #LightGreen {
    [Auth OAuth2]
    [CRUD APIs]
    [Storage]
    [Realtime]
    note right
      Gratuit jusqu&amp;#39;à 50k users
      Zéro configuration serveur
    end note
  }

  rectangle &amp;quot;業務バックエンド (スプリングブート)&amp;quot; #Coral {
    [Orchestration]
    [Jobs Planifiés]
    [Intégrations]
    [Transactions]
    note right
      Activé uniquement
      si nécessaire
    end note
  }

  database &amp;quot;PostgreSQL
唯一の真実のソース&amp;quot; as db #LightGray

  users --&amp;amp;gt; [JBake / GitHub Pages]

  [JBake / GitHub Pages] --&amp;amp;gt; [Auth OAuth2]
  [JBake / GitHub Pages] --&amp;amp;gt; [CRUD APIs]
  [JBake / GitHub Pages] --&amp;amp;gt; [Storage]
  [JBake / GitHub Pages] --&amp;amp;gt; [Realtime]
  [JBake / GitHub Pages] --&amp;amp;gt; [Orchestration]

  [Auth OAuth2] --&amp;amp;gt; db
  [CRUD APIs] --&amp;amp;gt; db
  [Orchestration] --&amp;amp;gt; db
  [Jobs Planifiés] --&amp;amp;gt; db
  [Intégrations] --&amp;amp;gt; db
}

note bottom of db
  **Une seule base, deux consommateurs**
  • Supabase pour le simple
  • Spring Boot pour le complexe
  • Aucune synchronisation requise
end note

@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_両方の世界のベスト&amp;quot;&amp;gt;両方の世界のベスト&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;このアーキテクチャは、あなたに与えます：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;🚀 Supabaseの速度&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;起動は時間単位、週単位ではない&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;数回クリックでOAuth2認証&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;自動生成されたREST API&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;ゼロ構成サーバー&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;💪 Spring Bootの力&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;Kotlin と コルーチン を使ったエレガントな非同期コード&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;複雑な業務プロセスのオーケストレーション&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;信頼できるスケジュールされたジョブ&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;ACIDトランザクションが保証されます&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;完全なSpringエコシステム&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;💰 プログレッシブ経済&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;0€開始および検証するために&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;成長に従うコスト&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;時期尚早な過剰設計なし&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;🎯 建築の柔軟性&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;段階的な移行、リフォームなし&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;Spring Boot は必要な場合のみ追加する&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;総ベンダーロックインはありません&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;進化的アーキテクチャ&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_さらに進む&amp;quot;&amp;gt;さらに進む&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_技術的リソース&amp;quot;&amp;gt;技術的リソース&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;Supabase ドキュメント :&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;https://supabase.com/docs/guides/auth&amp;quot;&amp;gt;認証ガイド&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;https://supabase.com/docs/guides/database/postgres/row-level-security&amp;quot;&amp;gt;行レベルセキュリティ&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;https://supabase.com/docs/guides/api&amp;quot;&amp;gt;自動生成されたAPI&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;Spring Boot ドキュメント :&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;https://spring.io/guides/tutorials/spring-boot-kotlin/&amp;quot;&amp;gt;Spring Boot と Kotlin&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;https://spring.io/blog/2019/04/12/going-reactive-with-spring-coroutines-and-kotlin-flow&amp;quot;&amp;gt;コルーチンとSpring&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;https://docs.spring.io/spring-security/reference/servlet/oauth2/resource-server/jwt.html&amp;quot;&amp;gt;JWT リソース サーバー&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;補足記事 :&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;JWTを使用したAPIセキュリティ&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;PostgreSQLのパフォーマンス最適化&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;段階的な移行パターン&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;分散アーキテクチャにおけるエラー管理&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_実際のユースケース&amp;quot;&amp;gt;実際のユースケース&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;このハイブリッドアーキテクチャは、以下で成功裏に使用されています :&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;SaaS B2B&amp;lt;/strong&amp;gt;: Supabase認証, Spring Boot 請求&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;マーケットプレイス&amp;lt;/strong&amp;gt;: Supabaseカタログ, Spring Bootのトランザクション&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;コンテンツプラットフォーム&amp;lt;/strong&amp;gt;: Supabase記事, Spring Bootアナリティクス&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;内部ツール&amp;lt;/strong&amp;gt;: CRUD Supabase, ワークフロー Spring Boot&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_スタートアップチェックリスト&amp;quot;&amp;gt;スタートアップチェックリスト&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;フェーズ 1 - 基礎 (第1週)&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;ulist checklist&amp;quot;&amp;gt;
&amp;lt;ul class=&amp;quot;checklist&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;i class=&amp;quot;fa fa-square-o&amp;quot;&amp;gt;&amp;lt;/i&amp;gt; Supabaseアカウントを作成 - [ ] PostgreSQL プロジェクトを設定する - [ ] 認証を有効にする (Google, GitHub) - [ ] 初期スキーマを定義 - [ ] Row Level Security を設定する - [ ] JBakeからAPIをテストする&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;フェーズ2 - MVP (第2-3週)&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;ulist checklist&amp;quot;&amp;gt;
&amp;lt;ul class=&amp;quot;checklist&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;i class=&amp;quot;fa fa-square-o&amp;quot;&amp;gt;&amp;lt;/i&amp;gt; 主要ページを実装する - [ ] OAuth2認証を統合する - [ ] CRUDフォームの作成 - [ ] ファイル用のストレージを設定 - [ ] GitHub Pagesにデプロイ - [ ] 実際の条件でテストする&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;フェーズ3 - 進化（ニーズに応じて）&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;ulist checklist&amp;quot;&amp;gt;
&amp;lt;ul class=&amp;quot;checklist&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;i class=&amp;quot;fa fa-square-o&amp;quot;&amp;gt;&amp;lt;/i&amp;gt; 複雑なロジックのニーズを特定 - [ ] 必要に応じて Spring Boot プロジェクトを作成 - [ ] スーパーベースのJWTバリデーションを設定する - [ ] Supabase PostgreSQLに接続 - [ ] 複雑な機能を移行する - [ ] スケジュールされたジョブを実装する - [ ] Spring Boot をデプロイ (Cloud Run など)&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_避けるべきアンチパターン&amp;quot;&amp;gt;避けるべきアンチパターン&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;❌ しないで :&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;SupabaseとSpring Boot間でデータを複製する&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;PostgreSQLの別々のデータベース2つを作成&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;自分で認証をコードしてください&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;Spring Bootを使ってシンプルなCRUDを実装する&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;最初からオーバーアーキテクトする&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;SupabaseのRow Level Securityを無視&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;むしろやる:&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;単一のPostgreSQLデータベースを共有する&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;Supabase に認証を任せる&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;Spring Bootを複雑さのためだけに使用する&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;シンプルに始めて、徐々に進化させる&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;各テクノロジーの強みを活用する&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;データベースレベルのRLSで保護する&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_進化の展望&amp;quot;&amp;gt;進化の展望&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_新しい機能の追加&amp;quot;&amp;gt;新しい機能の追加&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
skinparam backgroundColor #FEFEFE

rectangle &amp;quot;現在のアーキテクチャ&amp;quot; #SkyBlue {
  [JBake]
  [Supabase]
  [Spring Boot]
}

rectangle &amp;quot;可能な進化&amp;quot; #LightYellow {

  package &amp;quot;パフォーマンス&amp;quot; {
    [Redis Cache]
    [CDN pour Assets]
    [PostgreSQL Replicas]
  }

  package &amp;quot;モニタリング&amp;quot; {
    [Grafana]
    [Prometheus]
    [Sentry]
  }

  package &amp;quot;CI/CD&amp;quot; {
    [GitHub Actions]
    [Tests Automatisés]
    [Déploiement Continu]
  }

  package &amp;quot;機能&amp;quot; {
    [Search (ElasticSearch)]
    [Queue (RabbitMQ)]
    [Event Sourcing]
  }
}

[Spring Boot] .down.&amp;amp;gt; [Redis Cache] : Peut ajouter
[Spring Boot] .down.&amp;amp;gt; [Queue (RabbitMQ)] : Peut ajouter
[Spring Boot] .down.&amp;amp;gt; [Search (ElasticSearch)] : Peut ajouter

[Supabase] .down.&amp;amp;gt; [PostgreSQL Replicas] : Peut ajouter

note bottom
  **Architecture extensible**
  Chaque ajout est indépendant
  Pas de refonte globale nécessaire
end note
@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_水平スケーリング&amp;quot;&amp;gt;水平スケーリング&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;アプリケーションが成長すると、ハイブリッドアーキテクチャは自然にスケールします：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;Supabase：&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;自動的に何百万回もの操作にスケールします&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;読み取りレプリカ（読み取りパフォーマンス用）&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;セキュリティのためのポイントインタイムリカバリ&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;Spring Boot：&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;ロードバランサーの背後に複数のインスタンス&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;ステートレス設計は水平スケーリングを容易にする&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;必要に応じて、Kubernetesをオーケストレーションに使用する&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;PostgreSQL：&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;大規模なテーブル用のパーティショニング&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;接続プール (PgBouncer)&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;シャーディングは本当に必要です（稀）。&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_建築的証言&amp;quot;&amp;gt;建築的証言&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_スタートアップ_saas_50k_ユーザー&amp;quot;&amp;gt;スタートアップ SaaS (50k ユーザー)&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;em&amp;gt;&amp;lt;em&amp;gt;_ 私たちはSupabaseで100%スタートしました。5kユーザーに到達したとき、Stripeの請求と月次レポートのためだけにSpring Bootを追加しました。1年後、私たちの操作の80%はまだSupabaseを経由しています。Spring Bootはクリティカルな部分のみを管理します。この分離により、リファクタリングを行わずにスケールすることができました。 &amp;lt;/em&amp;gt;_&amp;lt;/em&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_eラーニングプラットフォーム_10k_ユーザー&amp;quot;&amp;gt;Eラーニングプラットフォーム (10k ユーザー)&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;em&amp;gt;&amp;lt;em&amp;gt;_ SupabaseのOAuth2認証により、開発に3週間の時間を節約できました。自動生成されたAPIが、コースカタログ全体を管理しています。Spring BootはPDF証明書と進捗メールにのみ使用されています。シンプルで保守性が高く、拡張性のあるアーキテクチャです。 &amp;lt;/em&amp;gt;_&amp;lt;/em&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_b2bマーケットプレイス3kユーザー&amp;quot;&amp;gt;B2Bマーケットプレイス（3kユーザー）&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;em&amp;gt;&amp;lt;em&amp;gt;_ Spring Bootは、買い手と売り手の間のトランザクションを管理します（重要）。Supabaseは、残りのすべてを管理します：プロフィール、リアルタイムメッセージング、ドキュメント。同じPostgreSQLデータベースを共有しているため、複雑な同期を避けることができます。これは、私たちがこれまでに行った中で最高のアーキテクチャ選択です。 &amp;lt;/em&amp;gt;_&amp;lt;/em&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_要約モダンな建築パラダイム&amp;quot;&amp;gt;要約：モダンな建築パラダイム&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;Supabase と Spring Boot を組み合わせたハイブリッド アーキテクチャは、新しいパラダイムを示しています：&amp;lt;strong&amp;gt;建築分野の専門化&amp;lt;/strong&amp;gt;。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
skinparam backgroundColor #FEFEFE

rectangle &amp;quot;古いパラダイム&amp;quot; #LightCoral {
  card &amp;quot;バックエンドの中のすべて&amp;quot; {
    [Auth]
    [CRUD]
    [Logique Métier]
    [Jobs]
    [Storage]
    [Realtime]
  }
  note bottom
    Complexité maximale
    dès le jour 1
  end note
}

rectangle &amp;quot;新しいパラダイム&amp;quot; #LightGreen {
  card &amp;quot;Supabase
(便利)&amp;quot; {
    [Auth]
    [CRUD Simple]
    [Storage]
    [Realtime]
  }

  card &amp;quot;Spring Boot
(差別化)&amp;quot; {
    [Logique Métier]
    [Jobs]
    [Intégrations]
  }

  note bottom
    Complexité progressive
    ajoutée seulement si nécessaire
  end note
}

[Ancien Paradigme] -right-&amp;amp;gt; [Nouveau Paradigme] : Évolution

@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;基本原理 :&amp;lt;/strong&amp;gt;既にサービスとして存在するものを構築しないでください。あなたのアプリケーションを差別化する点に集中してください。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_8020の法則&amp;quot;&amp;gt;80/20の法則&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;ほとんどのアプリケーションでは：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;80% の操作&amp;lt;/strong&amp;gt;標準のCRUDです → Supabase&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;20% の操作&amp;lt;/strong&amp;gt;ビジネスロジックが必要です → Spring Boot&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;この自然なルールはハイブリッドアーキテクチャを正当化します。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
skinparam backgroundColor #FEFEFE

package &amp;quot;作業の配分&amp;quot; {

  rectangle &amp;quot;80% - 標準操作&amp;quot; #LightGreen {
    [Lecture de données]
    [Création d&amp;#39;entités]
    [Mise à jour simple]
    [Suppression]
    [Upload fichiers]
    [Authentification]

    note bottom: **Géré par Supabase**
  }

  rectangle &amp;quot;20% - ビジネスロジック&amp;quot; #Coral {
    [Calculs complexes]
    [Workflows multi-étapes]
    [Transactions critiques]
    [Intégrations tierces]
    [Jobs planifiés]

    note bottom: **Géré par Spring Boot**
  }
}

note right
  **Focus optimal :**
  Votre temps de développement
  concentré sur les 20% qui
  différencient votre produit
end note
@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_最終結論&amp;quot;&amp;gt;最終結論&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;ハイブリッドアーキテクチャは技術的な妥協ではありません。それは&amp;lt;strong&amp;gt;戦略的決定&amp;lt;/strong&amp;gt;。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;したがって、あなたは以下のことができます：&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;✅ 機能的なMVPで素早く始める&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;�✅ 市場を検証する 重大な投資なしで&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;複雑さが求められるときに段階的に進化する&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;各段階でコストを管理する&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;各テクノロジーのベストを活用する&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;�✅ 過早なオーバーエンジニアリングを避ける&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;�✅ 将来のために柔軟性を保つ&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;彼女が表す：&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;🎯&amp;lt;strong&amp;gt;実用主義&amp;lt;/strong&amp;gt;彼女が得意とするすべての技術&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;🚀&amp;lt;strong&amp;gt;速度&amp;lt;/strong&amp;gt;: 最小のタイム・トゥ・マーケット&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;💰&amp;lt;strong&amp;gt;経済&amp;lt;/strong&amp;gt;価値に合わせたコスト&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;�🔮&amp;lt;strong&amp;gt;拡張性&amp;lt;/strong&amp;gt;: アーキテクチャはあなたと共に成長します&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;�🛡️&amp;lt;strong&amp;gt;堅牢性&amp;lt;/strong&amp;gt;実績のある信頼できるサービス&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_あなたの次のステップ&amp;quot;&amp;gt;あなたの次のステップ&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;このアーキテクチャがあなたに響くなら、ここで始める場所はこちらです：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;olist arabic&amp;quot;&amp;gt;
&amp;lt;ol class=&amp;quot;arabic&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;Supabaseアカウントを作成してください&amp;lt;/strong&amp;gt;(無料)&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;最小限のデータスキーマを定義してください&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;OAuth2認証を設定してください&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;最初のJBakeページを作成し、APIを消費する&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;GitHub Pagesにデプロイしてください&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ol&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;機能するMVPが手に入ります&amp;lt;strong&amp;gt;数日&amp;lt;/strong&amp;gt;.&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;Spring Boot は必要になったとき自然にやってきます。それより前ではない。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;hr&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;ハイブリッドアーキテクチャとは、必要なものを必要なときに正確に構築することである。&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;em&amp;gt;良い開発を！ 🚀&amp;lt;/em&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;hr&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;em&amp;gt;この記事を、他の開発者が適切なアーキテクチャの選択をするのに役立つと思う場合はシェアしてください。&amp;lt;/em&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;</description>
        </item><item>
            <title>ハイブリッドアーキテクチャ : Supabase と Spring Boot で実現する両方の良さ</title>
            <link >https://cheroliv.com/blog/2026/0100_jbake_supabase_springboot_hybride_post.html</link>
            <pubDate>Wed, 14 Jan 2026 00:00:00 +0000</pubDate>
            <guid isPermaLink="false">blog/2026/0100_jbake_supabase_springboot_hybride_post.html</guid>
            <description>&amp;lt;div id=&amp;quot;preamble&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;読了時間 : 12 minutes&amp;lt;/div&amp;gt;
&amp;lt;p&amp;gt;SupabaseのシンプルさとSpring Bootのパワーの間で選ぶのではなく、両方を組み合わせてみませんか？各テクノロジーの長所を活かしたハイブリッドアーキテクチャを見つけてください。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;dlist&amp;quot;&amp;gt;
&amp;lt;dl&amp;gt;
&amp;lt;dt class=&amp;quot;hdlist1&amp;quot;&amp;gt;コンコン&amp;lt;/dt&amp;gt;
&amp;lt;dd&amp;gt;
&amp;lt;p&amp;gt;[]&amp;lt;/p&amp;gt;
&amp;lt;/dd&amp;gt;
&amp;lt;/dl&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_現代建築の偽ジレンマ&amp;quot;&amp;gt;現代建築の偽ジレンマ&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;静的フロントエンドを使ってモダンなアプリケーションを構築する際、二者択一の選択肢に直面することがよくあります：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;バックエンド・アズ・ア・サービスソリューションにすべてを賭ける&amp;lt;/strong&amp;gt;(Supabase, Firebase) - シンプルだが制限がある&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;完全なバックエンドを構築する&amp;lt;/strong&amp;gt;(Spring Boot, Node.js) - 強力だが複雑&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;この選択は偽のジレンマです。ハイブリッドアーキテクチャは第三の道を提案します： &amp;lt;strong&amp;gt;各テクノロジーが最も得意とする場所で使用する&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_建築ビジョン&amp;quot;&amp;gt;建築ビジョン&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_伝統的アーキテクチャモノリシック&amp;quot;&amp;gt;伝統的アーキテクチャ：モノリシック&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
skinparam backgroundColor #FEFEFE
skinparam componentStyle rectangle

package &amp;quot;伝統的な建築&amp;quot; {
  actor Utilisateur as user
  component &amp;quot;フロントエンド&amp;quot; as frontend #LightBlue
  component &amp;quot;モノリシックバックエンド&amp;quot; as backend #LightCoral {
    [Authentification]
    [CRUD]
    [Logique Métier]
    [Jobs]
    [APIs Tierces]
  }
  database &amp;quot;データベース&amp;quot; as db #LightGray

  user --&amp;amp;gt; frontend
  frontend --&amp;amp;gt; backend : Toutes les requêtes
  backend --&amp;amp;gt; db
}

note right of backend
  Tout passe par le backend
  même les opérations simples

  ⚠️ Point de congestion unique
  ⚠️ Complexité dès le départ
  ⚠️ Couplage fort
end note
@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;このアプローチでは、記事の読み込みやコメントの作成など、最も単純な操作であってもすべてバックエンドを経由する必要があります。最初の日から複雑さのコストを支払うことになります。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_baasアーキテクチャ_すべての代表者&amp;quot;&amp;gt;BaaSアーキテクチャ: すべての代表者&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
skinparam backgroundColor #FEFEFE
skinparam componentStyle rectangle

package &amp;quot;�純粋なBaaSアーキテクチャ&amp;quot; {
  actor Utilisateur as user
  component &amp;quot;フロントエンド&amp;quot; as frontend #LightBlue
  cloud &amp;quot;Supabase / Firebase&amp;quot; as baas #LightGreen {
    [Auth]
    [Database]
    [Storage]
    [Edge Functions]
  }

  user --&amp;amp;gt; frontend
  frontend --&amp;amp;gt; baas : Toutes les opérations
}

note right of baas
  Développement rapide
  Pas de serveur à gérer

  ⚠️ Limité pour logique complexe
  ⚠️ Vendor lock-in
  ⚠️ Edge Functions contraintes
end note
@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;逆に、すべてを BaaS に委任することは最初は魅力的ですが、ビジネスロジックが複雑になるとすぐにその限界が見えてきます。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_ハイブリッドアーキテクチャ責任の分離&amp;quot;&amp;gt;ハイブリッドアーキテクチャ：責任の分離&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
skinparam backgroundColor #FEFEFE
skinparam componentStyle rectangle

actor Utilisateur as user #LightBlue

package &amp;quot;フロントエンド層&amp;quot; {
  component &amp;quot;JBake 静的サイト&amp;quot; as frontend #SkyBlue
}

package &amp;quot;シンプルな層 (Supabase)&amp;quot; #LightGreen {
  component &amp;quot;認証&amp;quot; as auth
  component &amp;quot;基本的なCRUD&amp;quot; as crud
  component &amp;quot;ファイルストレージ&amp;quot; as storage
  component &amp;quot;リアルタイム&amp;quot; as realtime
}

package &amp;quot;サービス層 (Spring Boot)&amp;quot; #Coral {
  component &amp;quot;複雑な論理&amp;quot; as logic
  component &amp;quot;オーケストレーション&amp;quot; as orchestration
  component &amp;quot;スケジュールされたジョブ&amp;quot; as jobs
  component &amp;quot;統合&amp;quot; as integrations
}

database &amp;quot;共有 PostgreSQL&amp;quot; as db #LightGray

user --&amp;amp;gt; frontend

frontend --&amp;amp;gt; auth : OAuth2, JWT
frontend --&amp;amp;gt; crud : Articles, Profils
frontend --&amp;amp;gt; storage : Images, Fichiers
frontend --&amp;amp;gt; realtime : Notifications

frontend --&amp;amp;gt; logic : Calculs, Rapports
frontend --&amp;amp;gt; orchestration : Workflows
logic --&amp;amp;gt; integrations : Stripe, APIs
orchestration --&amp;amp;gt; db
jobs --&amp;amp;gt; db

crud --&amp;amp;gt; db
auth --&amp;amp;gt; db

note bottom of db
  **Une seule source de vérité**
  Partagée entre Supabase et Spring Boot
end note

note right of auth
  **Gratuit jusqu&amp;#39;à 50k users**
  Configuration en quelques clics
  OAuth2 multi-providers
end note

note right of logic
  **Activé seulement si nécessaire**
  Kotlin + Coroutines
  Transactions complexes
end note
@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;ハイブリッドアーキテクチャは、操作の複雑さと性質に応じて、責任を明確に分離します。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_設計原則&amp;quot;&amp;gt;設計原則&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_原則1シンプルに始め賢く進化させる&amp;quot;&amp;gt;原則1：シンプルに始め、賢く進化させる&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
skinparam backgroundColor #FEFEFE

rectangle &amp;quot;**フェーズ 1 : MVP**&amp;quot; #LightGreen {
  component &amp;quot;JBake + Supabase&amp;quot; as mvp
  note right
    ✓ Développement en jours
    ✓ Coût : 0€
    ✓ Validation concept
  end note
}

rectangle &amp;quot;フェーズ2：成長&amp;quot; #LightYellow {
  component &amp;quot;JBake + Supabase
+ Spring Boot (オプション)&amp;quot; as growth
  note right
    ✓ Logique métier émerge
    ✓ Premiers jobs planifiés
    ✓ Intégrations tierces
  end note
}

rectangle &amp;quot;フェーズ 3 : スケール&amp;quot; #LightCoral {
  component &amp;quot;完全なアーキテクチャ&amp;quot; as scale
  note right
    ✓ Orchestration complexe
    ✓ Performances optimisées
    ✓ Cache distribué
  end note
}

mvp -down-&amp;amp;gt; growth : Quand la complexité\nle justifie
growth -down-&amp;amp;gt; scale : Optimisation\ncontinue
@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;必要がない場合は、Spring Bootをビルドしないでください。&amp;lt;/strong&amp;gt;Supabaseで始めて、複雑さがそれを正当化するならSpring Bootを追加してください。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_原則2_業務の性質による分離&amp;quot;&amp;gt;原則2 : 業務の性質による分離&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startmindmap
skinparam backgroundColor #FEFEFE
* Opérations\nApplicatives

left side

** Opérations Simples\n(Supabase)
***_ CRUD Standard
****_ Lecture
****_ Création
****_ Mise à jour
****_ Suppression
***_ Authentification
****_ Login/Logout
****_ OAuth2
****_ Gestion session
***_ Stockage
****_ Upload fichiers
****_ CDN automatique
***_ Temps Réel
****_ WebSocket
****_ Notifications

right side

** Opérations Complexes\n(Spring Boot)
***_ Logique Métier
****_ Calculs complexes
****_ Règles métier
****_ Validations avancées
***_ Orchestration
****_ Multi-services
****_ Transactions distribuées
****_ Saga patterns
***_ Tâches Planifiées
****_ Rapports périodiques
****_ Synchronisations
****_ Nettoyages
***_ Intégrations
****_ Paiements (Stripe)
****_ APIs tierces
****_ Services ML/AI

@endmindmap&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_原則3唯一の真実のソース&amp;quot;&amp;gt;原則3：唯一の真実のソース&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
skinparam backgroundColor #FEFEFE

database &amp;quot;PostgreSQL&amp;quot; as db #LightGray {
  package &amp;quot;スキーマ: auth (Supabase)&amp;quot; #LightGreen {
    [users]
    [sessions]
    [identities]
  }

  package &amp;quot;スキーマ: 公開 (共有)&amp;quot; #SkyBlue {
    [articles]
    [comments]
    [profiles]
  }

  package &amp;quot;スキーマ: ビジネス (Spring Boot)&amp;quot; #Coral {
    [orders]
    [payments]
    [reports]
  }
}

component &amp;quot;サプベース&amp;quot; as supabase #LightGreen
component &amp;quot;スプリングブート&amp;quot; as spring #Coral

supabase -down-&amp;amp;gt; users : Gère
supabase -down-&amp;amp;gt; sessions : Gère
supabase -down-&amp;amp;gt; articles : Accède
supabase -down-&amp;amp;gt; comments : Accède
supabase -down-&amp;amp;gt; profiles : Accède

spring -down-&amp;amp;gt; articles : Accède
spring -down-&amp;amp;gt; profiles : Accède
spring -down-&amp;amp;gt; orders : Gère
spring -down-&amp;amp;gt; payments : Gère
spring -down-&amp;amp;gt; reports : Gère

note right of db
  **Avantages :**
  • Pas de synchronisation complexe
  • JOINs possibles entre tables
  • Cohérence garantie
  • Migrations unifiées
end note
@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;SupabaseとSpring Bootは同じPostgreSQLインスタンスを共有することで、複雑な同期なしに同じデータ上で作業します。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_フラックスのオーケストレーション&amp;quot;&amp;gt;フラックスのオーケストレーション&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_フラックス_1_中央集中型認証&amp;quot;&amp;gt;フラックス 1 : 中央集中型認証&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
skinparam backgroundColor #FEFEFE
autonumber

actor &amp;quot;ユーザー&amp;quot; as user
participant &amp;quot;JBake&amp;quot; as jbake
participant &amp;quot;Supabase Auth&amp;quot; as auth
participant &amp;quot;スプリングブート&amp;quot; as spring
database &amp;quot;PostgreSQL&amp;quot; as db

== Authentification ==
user -&amp;amp;gt; jbake : Clique &amp;quot;ログイン&amp;quot;
jbake -&amp;amp;gt; auth : Redirect OAuth2 (Google/GitHub)
auth -&amp;amp;gt; user : Consent screen
user -&amp;amp;gt; auth : Autorise
auth -&amp;amp;gt; auth : Génère JWT
auth -&amp;amp;gt; jbake : Retourne JWT + Refresh Token
jbake -&amp;amp;gt; jbake : Stocke tokens (sessionStorage)

== Accès aux Ressources ==
group Opération Simple (CRUD)
  user -&amp;amp;gt; jbake : Crée un article
  jbake -&amp;amp;gt; db : POST avec JWT
  note right: Supabase Row Level Security\nvérifie le JWT automatiquement
  db -&amp;amp;gt; jbake : Article créé
end

group Opération Complexe (Métier)
  user -&amp;amp;gt; jbake : Génère un rapport
  jbake -&amp;amp;gt; spring : POST /api/reports\navec JWT
  spring -&amp;amp;gt; spring : Valide JWT Supabase
  spring -&amp;amp;gt; spring : Extrait claims (user_id, roles)
  spring -&amp;amp;gt; db : Requêtes complexes
  spring -&amp;amp;gt; jbake : Rapport généré
end

note over auth, spring
  **Le JWT est universel**
  Valide par Supabase ET Spring Boot
  Pas de double authentification
end note
@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;重要な点&amp;lt;/strong&amp;gt;: 一つの認証プロセス、一つのJWT、どこでも利用可能。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_フラックス2複雑なビジネスプロセスのオーケストレーション&amp;quot;&amp;gt;フラックス2：複雑なビジネスプロセスのオーケストレーション&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
skinparam backgroundColor #FEFEFE
autonumber

actor &amp;quot;クライアント&amp;quot; as user
participant &amp;quot;JBake&amp;quot; as jbake
participant &amp;quot;スプリングブート&amp;quot; as spring
participant &amp;quot;Supabase データベース&amp;quot; as supadb
participant &amp;quot;StripeのAPI&amp;quot; as stripe
participant &amp;quot;在庫サービス&amp;quot; as inventory
participant &amp;quot;メールサービス&amp;quot; as email
database &amp;quot;PostgreSQL&amp;quot; as db

user -&amp;amp;gt; jbake : Passe commande
jbake -&amp;amp;gt; spring : POST /api/orders/create

== Orchestration Spring Boot ==
spring -&amp;amp;gt; db : BEGIN TRANSACTION

par Vérifications Parallèles
  spring -&amp;amp;gt; inventory : Vérifier stock
  inventory -&amp;amp;gt; spring : Stock OK
else
  spring -&amp;amp;gt; db : Vérifier profil client
  db -&amp;amp;gt; spring : Client vérifié
end

spring -&amp;amp;gt; stripe : Créer Payment Intent
stripe -&amp;amp;gt; spring : Intent créé (ID: pi_xxx)

spring -&amp;amp;gt; db : Créer Order (status: PENDING)
db -&amp;amp;gt; spring : Order créé

spring -&amp;amp;gt; stripe : Confirmer paiement
stripe -&amp;amp;gt; spring : Paiement confirmé

spring -&amp;amp;gt; db : Update Order (status: PAID)
spring -&amp;amp;gt; inventory : Décrémenter stock
spring -&amp;amp;gt; db : COMMIT TRANSACTION

par Notifications Asynchrones
  spring -&amp;amp;gt; email : Email confirmation
else
  spring -&amp;amp;gt; supadb : Insert notification
  note right: Notification temps réel\nvia Supabase Realtime
end

spring -&amp;amp;gt; jbake : Order confirmé
jbake -&amp;amp;gt; user : Affiche confirmation

note over spring
  **Responsabilités Spring Boot :**
  • Transaction ACID
  • Orchestration multi-services
  • Rollback automatique si erreur
  • Gestion des cas limites
end note
@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;Spring Bootが提供するもの&amp;lt;/strong&amp;gt;複数のシステムに関わる複雑なプロセスの信頼性の高いオーケストレーションおよびトランザクション保証。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_フラックス_3_予定されたジョブと同期&amp;quot;&amp;gt;フラックス 3 : 予定されたジョブと同期&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
skinparam backgroundColor #FEFEFE

participant &amp;quot;スケジューラー\n(Spring Boot)&amp;quot; as scheduler
participant &amp;quot;レポートサービス&amp;quot; as report
participant &amp;quot;PostgreSQL&amp;quot; as db
participant &amp;quot;外部 API&amp;quot; as api
participant &amp;quot;メールサービス&amp;quot; as email
participant &amp;quot;Supabase ストレージ&amp;quot; as storage

== Job Quotidien : 2h00 ==
activate scheduler
scheduler -&amp;amp;gt; report : Déclenche génération rapport

activate report
report -&amp;amp;gt; db : Récupère données\ndes dernières 24h
db -&amp;amp;gt; report : Dataset

report -&amp;amp;gt; report : Calculs &amp;amp;amp; Agrégations
report -&amp;amp;gt; report : Génération PDF

report -&amp;amp;gt; storage : Upload PDF
storage -&amp;amp;gt; report : URL publique

report -&amp;amp;gt; email : Envoie aux admins\navec lien PDF
deactivate report

== Job Hebdomadaire : Dimanche 3h00 ==
scheduler -&amp;amp;gt; report : Synchronisation externe

activate report
report -&amp;amp;gt; api : Fetch données externes
api -&amp;amp;gt; report : Nouvelles données

report -&amp;amp;gt; db : Mise à jour tables
report -&amp;amp;gt; db : Nettoyage données obsolètes
deactivate report

== Job Mensuel : 1er du mois ==
scheduler -&amp;amp;gt; report : Facturation

activate report
report -&amp;amp;gt; db : Liste clients actifs
report -&amp;amp;gt; report : Calcul montants
report -&amp;amp;gt; api : Génération factures (Stripe)
report -&amp;amp;gt; email : Envoi factures
deactivate report

deactivate scheduler

note right of scheduler
  **Impossible avec Supabase seul**
  Edge Functions non adaptées
  pour jobs longs et récurrents
end note
@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;Spring Bootがもたらすもの&amp;lt;/strong&amp;gt;: 信頼性の高いスケジュールされたジョブ、状態管理、自動リトライ、保証された実行&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_意思決定マトリックス&amp;quot;&amp;gt;意思決定マトリックス&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_supabase_を使うべきときは&amp;quot;&amp;gt;Supabase を使うべきときは？&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
skinparam backgroundColor #FEFEFE

start

:Nouvelle fonctionnalité à implémenter;

if (CRUD simple ?) then (oui)
  :✅ **Supabase**;
  stop
else (non)
  if (Authentification ?) then (oui)
    :✅ **Supabase Auth**;
    stop
  else (non)
    if (Upload fichiers ?) then (oui)
      :✅ **Supabase Storage**;
      stop
    else (non)
      if (Temps réel ?) then (oui)
        :✅ **Supabase Realtime**;
        stop
      else (non)
        if (Row Level Security\nsuffisante ?) then (oui)
          :✅ **Supabase + Policies**;
          stop
        else (non)
          :⚠️ **Considérer Spring Boot**;
          #Coral:Passer à l&amp;#39;arbre\nde décision Spring Boot;
          stop
        endif
      endif
    endif
  endif
endif

@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_spring_boot_を使用するのはいつですか&amp;quot;&amp;gt;Spring Boot を使用するのはいつですか？&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
skinparam backgroundColor #FEFEFE

start

:Nouvelle fonctionnalité complexe;

if (Orchestration\nmulti-services ?) then (oui)
  :✅ **Spring Boot**;
  stop
else (non)
  if (Transaction ACID\ncritique ?) then (oui)
    :✅ **Spring Boot**;
    stop
  else (non)
    if (Job planifié ?) then (oui)
      :✅ **Spring Boot Scheduler**;
      stop
    else (non)
      if (Intégration API\ntierce complexe ?) then (oui)
        :✅ **Spring Boot**;
        stop
      else (non)
        if (Calculs lourds\n&amp;amp;gt; 10 secondes ?) then (oui)
          :✅ **Spring Boot**;
          stop
        else (non)
          if (Cache distribué\nnécessaire ?) then (oui)
            :✅ **Spring Boot + Redis**;
            stop
          else (non)
            :⚠️ **Probablement Supabase**;
            #LightGreen:Revenir à l&amp;#39;arbre\nde décision Supabase;
            stop
          endif
        endif
      endif
    endif
  endif
endif

@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_プロジェクトタイプ別のアーキテクチャ例&amp;quot;&amp;gt;プロジェクトタイプ別のアーキテクチャ例&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_ブログ_ポートフォリオ&amp;quot;&amp;gt;ブログ / ポートフォリオ&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
skinparam backgroundColor #FEFEFE
skinparam componentStyle rectangle

package &amp;quot;個人ブログ - 95% Supabase&amp;quot; {
  component &amp;quot;JBake&amp;quot; as jbake #SkyBlue

  package &amp;quot;Supabase (無料)&amp;quot; #LightGreen {
    [Auth: OAuth2 Google]
    [Articles (CRUD)]
    [Commentaires]
    [Images (Storage)]
    [Notifications Realtime]
  }

  package &amp;quot;Spring Boot (オプション)&amp;quot; #LightCoral {
    [Newsletter Mensuelle]
    note bottom: Job planifié uniquement
  }

  database &amp;quot;PostgreSQL&amp;quot; as db

  jbake --&amp;amp;gt; [Auth: OAuth2 Google]
  jbake --&amp;amp;gt; [Articles (CRUD)]
  jbake --&amp;amp;gt; [Commentaires]
  jbake --&amp;amp;gt; [Images (Storage)]
  jbake --&amp;amp;gt; [Notifications Realtime]

  [Articles (CRUD)] --&amp;amp;gt; db
  [Commentaires] --&amp;amp;gt; db
  [Newsletter Mensuelle] --&amp;amp;gt; db
}

note bottom of &amp;quot;Spring Boot (オプション)&amp;quot;
  **Spring Boot pas obligatoire**
  Newsletter peut être gérée
  par un service tiers (Mailchimp)
end note
@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;判決&amp;lt;/strong&amp;gt;: 100% Supabaseは十分以上です。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_saasアプリケーション&amp;quot;&amp;gt;SaaSアプリケーション&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
skinparam backgroundColor #FEFEFE
skinparam componentStyle rectangle

package &amp;quot;SaaSアプリケーション-ハイブリッドアーキテクチャー&amp;quot; {
  component &amp;quot;JBake / React&amp;quot; as frontend #SkyBlue

  package &amp;quot;スパベース&amp;quot; #LightGreen {
    [Auth Multi-tenant]
    [Profils Utilisateurs]
    [Données Simples]
    [Storage Documents]
  }

  package &amp;quot;スプリングブート&amp;quot; #Coral {
    [Facturation (Stripe)]
    [Analytics Avancées]
    [Rapports Mensuels]
    [Quotas &amp;amp;amp; Limites]
    [Webhooks Stripe]
  }

  cloud &amp;quot;外部サービス&amp;quot; {
    [Stripe API]
    [SendGrid Email]
  }

  database &amp;quot;PostgreSQL 共有&amp;quot; as db

  frontend --&amp;amp;gt; [Auth Multi-tenant]
  frontend --&amp;amp;gt; [Profils Utilisateurs]
  frontend --&amp;amp;gt; [Données Simples]
  frontend --&amp;amp;gt; [Facturation (Stripe)]
  frontend --&amp;amp;gt; [Analytics Avancées]

  [Auth Multi-tenant] --&amp;amp;gt; db
  [Profils Utilisateurs] --&amp;amp;gt; db
  [Données Simples] --&amp;amp;gt; db

  [Facturation (Stripe)] --&amp;amp;gt; db
  [Facturation (Stripe)] --&amp;amp;gt; [Stripe API]
  [Analytics Avancées] --&amp;amp;gt; db
  [Rapports Mensuels] --&amp;amp;gt; db
  [Rapports Mensuels] --&amp;amp;gt; [SendGrid Email]
  [Webhooks Stripe] ..&amp;amp;gt; [Stripe API] : Écoute
}

note right of &amp;quot;スプリングブート&amp;quot;
  **Nécessaire pour :**
  • Gestion abonnements
  • Facturation récurrente
  • Quotas dynamiques
  • Analytics complexes
  • Webhooks fiables
end note
@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;評決&amp;lt;/strong&amp;gt;: ハイブリッドアーキテクチャが必要です。Supabaseは基本部分に、Spring Bootはクリティカルな部分（支払い、請求）に使用します。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_eコマース&amp;quot;&amp;gt;Eコマース&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
skinparam backgroundColor #FEFEFE
skinparam componentStyle rectangle

package &amp;quot;Eコマース - 70% Spring Boot&amp;quot; {
  component &amp;quot;ストアフロント (JBake/React)&amp;quot; as frontend #SkyBlue

  package &amp;quot;サプベース&amp;quot; #LightGreen {
    [Auth Clients]
    [Catalogue Produits\n(lecture seule)]
    [Images Produits]
  }

  package &amp;quot;Spring Boot (コアビジネス)&amp;quot; #Coral {
    [Gestion Commandes]
    [Paiements Stripe]
    [Gestion Stock]
    [Calcul Frais Port]
    [Génération Factures]
    [Synchronisation ERP]
    [Emails Transactionnels]
  }

  cloud &amp;quot;統合&amp;quot; {
    [Stripe]
    [Transporteur API]
    [ERP Externe]
  }

  database &amp;quot;PostgreSQL&amp;quot; as db

  frontend --&amp;amp;gt; [Auth Clients]
  frontend --&amp;amp;gt; [Catalogue Produits\n(lecture seule)]
  frontend --&amp;amp;gt; [Gestion Commandes]

  [Auth Clients] --&amp;amp;gt; db
  [Catalogue Produits\n(lecture seule)] --&amp;amp;gt; db

  [Gestion Commandes] --&amp;amp;gt; db
  [Paiements Stripe] --&amp;amp;gt; [Stripe]
  [Gestion Stock] --&amp;amp;gt; db
  [Calcul Frais Port] --&amp;amp;gt; [Transporteur API]
  [Génération Factures] --&amp;amp;gt; db
  [Synchronisation ERP] --&amp;amp;gt; [ERP Externe]
  [Synchronisation ERP] --&amp;amp;gt; db
}

note right of &amp;quot;Spring Boot (コアビジネス)&amp;quot;
  **Spring Boot indispensable :**
  • Transactions critiques
  • Orchestration complexe
  • Intégrations multiples
  • Conformité légale
  • Jobs de synchronisation
end note
@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;判決&amp;lt;/strong&amp;gt;Spring Boot は必須です。Supabase は認証とカタログのみに使用します。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_段階的移行戦略&amp;quot;&amp;gt;段階的移行戦略&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
skinparam backgroundColor #FEFEFE

|Semaine 1-2|
start
:Créer projet Supabase;
:Configurer Auth (Google, GitHub);
:Définir schéma PostgreSQL initial;
:Implémenter CRUD de base sur JBake;
:Déployer MVP sur GitHub Pages;
note right
  **Livrable :** Application fonctionnelle
  **Coût :** 0€
  **Temps :** 1-2 semaines
end note

|Semaine 3-4|
:Observer utilisation réelle;
:Identifier limitations;

|Décision|
if (Logique complexe\némerge ?) then (non)
  |Supabase|
  :Continuer avec Supabase seul;
  :Ajouter Edge Functions si besoin;
  stop
else (oui)
  |Spring Boot|
  :Créer projet Spring Boot;
  :Configurer validation JWT Supabase;
  :Migrer logique complexe vers Spring Boot;
  note right
    **Migration sélective**
    Seulement ce qui est complexe
  end note
endif

|Semaines suivantes|
:Déployer Spring Boot (Cloud Run, EC2);
:Connecter à PostgreSQL Supabase;
:Implémenter premiers jobs planifiés;
:Intégrer APIs tierces;

stop

note right
  **Architecture finale hybride**
  Supabase + Spring Boot
  en parfaite harmonie
end note
@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_コストおよび運用上の考慮事項&amp;quot;&amp;gt;コストおよび運用上の考慮事項&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_コスト構造&amp;quot;&amp;gt;コスト構造&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
skinparam backgroundColor #FEFEFE

package &amp;quot;推定月間コスト&amp;quot; {

  rectangle &amp;quot;MVP フェーズ
(0-1000 ユーザー)&amp;quot; #LightGreen {
    [JBake (GitHub Pages): 0€]
    [Supabase: 0€]
    [Spring Boot: N/A]
    note bottom: **Total: 0€/mois**
  }

  rectangle &amp;quot;成長フェーズ\n(1k-10k ユーザー)&amp;quot; #LightYellow {
    [JBake (GitHub Pages): 0€]
    [Supabase: 0€]
    [Spring Boot (Cloud Run): 20-50€]
    [PostgreSQL (si séparé): 0-30€]
    note bottom: **Total: 20-80€/mois**
  }

  rectangle &amp;quot;フェーズスケール
(10k-100k ユーザー)&amp;quot; #LightCoral {
    [JBake (Netlify Pro): 19€]
    [Supabase Pro: 25€]
    [Spring Boot (instances multiples): 100-300€]
    [Redis Cache: 20-50€]
    [Monitoring: 20€]
    note bottom: **Total: 184-414€/mois**
  }
}

note right of &amp;quot;フェーズスケール
(10k-100k ユーザー)&amp;quot;
  À ce stade, les revenus
  justifient largement les coûts
end note
@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_運営上の責任&amp;quot;&amp;gt;運営上の責任&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
skinparam backgroundColor #FEFEFE

package &amp;quot;誰が何を管理しているのか？&amp;quot; {

  rectangle &amp;quot;Supabase が管理 (0 労力)&amp;quot; #LightGreen {
    [Authentification]
    [Base de données]
    [Backups automatiques]
    [Scaling automatique]
    [Monitoring DB]
    [Sécurité DB]
  }

  rectangle &amp;quot;GitHubによって管理 (0 労力)&amp;quot; #SkyBlue {
    [Hébergement site statique]
    [HTTPS/SSL]
    [CDN global]
    [Déploiement automatique]
  }

  rectangle &amp;quot;管理 (Spring Boot)&amp;quot; #LightCoral {
    [Déploiement application]
    [Monitoring APM]
    [Logs centralisés]
    [Scaling horizontal]
    [Mises à jour sécurité]
  }
}

note bottom of &amp;quot;管理 (Spring Boot)&amp;quot;
  **Minimisable avec :**
  • Cloud Run (serverless)
  • Kubernetes (si nécessaire)
  • Services managés (RDS, etc.)
end note
@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_結論完璧なバランス&amp;quot;&amp;gt;結論：完璧なバランス&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;Supabase + Spring Bootのハイブリッドアーキテクチャは妥協ではなく、それは&amp;lt;strong&amp;gt;シナジー&amp;lt;/strong&amp;gt;.&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_覚えておくべき原則&amp;quot;&amp;gt;覚えておくべき原則&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startmindmap
skinparam backgroundColor #FEFEFE
* Architecture\nHybride

** Commencer Simple
***_ MVP avec Supabase
***_ 0€ de coût initial
***_ Validation rapide

** Évoluer Intelligemment
***_ Ajouter Spring Boot\nsi nécessaire
***_ Migration progressive
***_ Pas de refonte totale

** Exploiter les Forces
***_ Supabase: Simplicité
***_ Spring Boot: Puissance
***_ PostgreSQL: Source unique

** Minimiser la Complexité
***_ Pas de synchronisation
***_ Pas de duplication
***_ Architecture claire

** Optimiser les Coûts
***_ Gratuit au départ
***_ Scaling progressif
***_ ROI évident

@endmindmap&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_このアーキテクチャを選択するのはいつですか&amp;quot;&amp;gt;このアーキテクチャを選択するのはいつですか？&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;�✅ このアーキテクチャは次の場合に理想的です :&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;すぐに始めたい(MVPは日で、月ではない)&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;業務の複雑さが増加すると予測しています&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;初期コストを最小限に抑えたい&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;PostgreSQLが好きで、単一の真実のソースを望んでいます&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;あなたはビジネスコードのためにKotlinとコルーチンが好きです&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;あなたは完全なベンダーロックインを避けたいです&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;�❌ このアーキテクチャは適していない場合：&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;あなたのプロジェクトはシンプルで、そのままです（個人ブログ → Supabase 100% で十分）&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;あなたはすでにマスターしている確立されたバックエンドスタックを持っています&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;あなたは伝統的なモノリスを好む&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;.NET、Python、またはその他のバックエンド言語が必要です。&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_最終的な全体像&amp;quot;&amp;gt;最終的な全体像&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
skinparam backgroundColor #FEFEFE

package &amp;quot;完全なハイブリッドアーキテクチャ&amp;quot; {

  actor &amp;quot;利用者&amp;quot; as users

  rectangle &amp;quot;フロントエンド (静的)&amp;quot; #SkyBlue {
    [JBake / GitHub Pages]
    note right: Gratuit, CDN global
  }

  rectangle &amp;quot;バックエンド シンプル (Supabase)&amp;quot; #LightGreen {
    [Auth OAuth2]
    [CRUD APIs]
    [Storage]
    [Realtime]
    note right
      Gratuit jusqu&amp;#39;à 50k users
      Zéro configuration serveur
    end note
  }

  rectangle &amp;quot;ビジネスバックエンド (Spring Boot)&amp;quot; #Coral {
    [Orchestration]
    [Jobs Planifiés]
    [Intégrations]
    [Transactions]
    note right
      Activé uniquement
      si nécessaire
    end note
  }

  database &amp;quot;PostgreSQL
唯一の真実のソース&amp;quot; as db #LightGray

  users --&amp;amp;gt; [JBake / GitHub Pages]

  [JBake / GitHub Pages] --&amp;amp;gt; [Auth OAuth2]
  [JBake / GitHub Pages] --&amp;amp;gt; [CRUD APIs]
  [JBake / GitHub Pages] --&amp;amp;gt; [Storage]
  [JBake / GitHub Pages] --&amp;amp;gt; [Realtime]
  [JBake / GitHub Pages] --&amp;amp;gt; [Orchestration]

  [Auth OAuth2] --&amp;amp;gt; db
  [CRUD APIs] --&amp;amp;gt; db
  [Orchestration] --&amp;amp;gt; db
  [Jobs Planifiés] --&amp;amp;gt; db
  [Intégrations] --&amp;amp;gt; db
}

note bottom of db
  **Une seule base, deux consommateurs**
  • Supabase pour le simple
  • Spring Boot pour le complexe
  • Aucune synchronisation requise
end note

@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_両方の世界の最高&amp;quot;&amp;gt;両方の世界の最高&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;このアーキテクチャは以下を提供します :&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;�🚀 Supabaseの速度&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;起動は時間単位で、週単位ではない&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;OAuth2認証を数クリックで&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;自動生成されたREST API&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;サーバーのゼロ構成&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;💪 Spring Bootのパワー&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;Kotlinとコルーチンによるエレガントな非同期コード&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;複雑なビジネスプロセスのオーケストレーション&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;信頼できるスケジュールされたジョブ&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;ACIDトランザクションの保証&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;完全なSpringエコシステム&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;💰 進歩的な経済&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;0€で開始し、確認&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;成長に追随するコスト&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;過早なオーバーエンジニアリングはしない&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;�🎯 アーキテクチャの柔軟性&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;段階的な移行、リファクタリングなし&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;必要な場合のみSpring Bootを追加&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;完全なベンダーロックインはありません&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;進化するアーキテクチャ&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_さらに進む&amp;quot;&amp;gt;さらに進む&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_技術的リソース&amp;quot;&amp;gt;技術的リソース&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;Supabaseドキュメント：&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;https://supabase.com/docs/guides/auth&amp;quot;&amp;gt;認証ガイド&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;https://supabase.com/docs/guides/database/postgres/row-level-security&amp;quot;&amp;gt;行レベルセキュリティ&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;https://supabase.com/docs/guides/api&amp;quot;&amp;gt;自動生成されたAPI&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;Spring Boot ドキュメント :&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;https://spring.io/guides/tutorials/spring-boot-kotlin/&amp;quot;&amp;gt;Spring Boot と Kotlin&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;https://spring.io/blog/2019/04/12/going-reactive-with-spring-coroutines-and-kotlin-flow&amp;quot;&amp;gt;コルーチンとSpring&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;https://docs.spring.io/spring-security/reference/servlet/oauth2/resource-server/jwt.html&amp;quot;&amp;gt;JWT リソース サーバー&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;補足記事：&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;JWTを使用したAPIのセキュリティ&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;PostgreSQLのパフォーマンス最適化&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;段階的移行パターン&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;分散アーキテクチャにおけるエラー管理&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_実際の使用例&amp;quot;&amp;gt;実際の使用例&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;このハイブリッドアーキテクチャは、以下で正常に使用されています：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;SaaS B2B&amp;lt;/strong&amp;gt;: 認証 Supabase, 請求 Spring Boot&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;マーケットプレイス&amp;lt;/strong&amp;gt;: カタログSupabase, トランザクションSpring Boot&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;コンテンツプラットフォーム&amp;lt;/strong&amp;gt;: Supabase の記事、Spring Boot の分析&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;内部ツール&amp;lt;/strong&amp;gt;SupabaseのCRUD、Spring Bootのワークフロー&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_起動チェックリスト&amp;quot;&amp;gt;起動チェックリスト&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;フェーズ 1 - 基盤 (第1週)&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;ulist checklist&amp;quot;&amp;gt;
&amp;lt;ul class=&amp;quot;checklist&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;i class=&amp;quot;fa fa-square-o&amp;quot;&amp;gt;&amp;lt;/i&amp;gt; Supabaseアカウントを作成 - [ ] PostgreSQL プロジェクトを設定する - [ ] 認証を有効にする(Google, GitHub) - [ ] 初期スキーマを定義する - [ ] Row Level Security を設定 - [ ] JBakeからAPIをテストする&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;Phase 2 - MVP (第2-3週)&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;ulist checklist&amp;quot;&amp;gt;
&amp;lt;ul class=&amp;quot;checklist&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;i class=&amp;quot;fa fa-square-o&amp;quot;&amp;gt;&amp;lt;/i&amp;gt; 主要なページを実装する - [ ] OAuth2認証を統合する - [ ] CRUDフォームを作成 - [ ] ストレージをファイル用に設定する - [ ] GitHub Pages にデプロイする - [ ] 実際の条件でテストする&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;フェーズ 3 - 進化 (必要に応じて)&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;ulist checklist&amp;quot;&amp;gt;
&amp;lt;ul class=&amp;quot;checklist&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;i class=&amp;quot;fa fa-square-o&amp;quot;&amp;gt;&amp;lt;/i&amp;gt; 複雑なロジックのニーズを特定する - [ ] 必要に応じてSpring Bootプロジェクトを作成する - [ ] Supabase の JWT 検証を設定 - [ ] Supabase PostgreSQL に接続 - [ ] 複雑な機能を移行 - [ ] スケジュールされたジョブを実装する - [ ] デプロイ: Spring Boot (Cloud Run など)&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_避けるべきアンチパターン&amp;quot;&amp;gt;�避けるべきアンチパターン&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;�❌ しないでください：&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;Supabase と Spring Boot の間でデータを複製する&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;2つの別々のPostgreSQL データベースを作成する&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;認証を自分でコードする&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;Spring Boot を使用してシンプルな CRUD を行う&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;開始からオーバーアーキテクチャーする&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;SupabaseのRow Level Securityを無視&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;✅ むしろする :&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;1つのPostgreSQLデータベースを共有&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;Supabase に認証を任せる&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;複雑さのためだけに Spring Boot を使用する&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;シンプルに始め、段階的に進化させる&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;各技術の強みを活かす&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;データベースレベルでRLSを使用して保護する&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_進化の展望&amp;quot;&amp;gt;進化の展望&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_新機能の追加&amp;quot;&amp;gt;新機能の追加&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
skinparam backgroundColor #FEFEFE

rectangle &amp;quot;現代建築&amp;quot; #SkyBlue {
  [JBake]
  [Supabase]
  [Spring Boot]
}

rectangle &amp;quot;可能な進化&amp;quot; #LightYellow {

  package &amp;quot;パフォーマンス&amp;quot; {
    [Redis Cache]
    [CDN pour Assets]
    [PostgreSQL Replicas]
  }

  package &amp;quot;監視&amp;quot; {
    [Grafana]
    [Prometheus]
    [Sentry]
  }

  package &amp;quot;CI/CD&amp;quot; {
    [GitHub Actions]
    [Tests Automatisés]
    [Déploiement Continu]
  }

  package &amp;quot;機能&amp;quot; {
    [Search (ElasticSearch)]
    [Queue (RabbitMQ)]
    [Event Sourcing]
  }
}

[Spring Boot] .down.&amp;amp;gt; [Redis Cache] : Peut ajouter
[Spring Boot] .down.&amp;amp;gt; [Queue (RabbitMQ)] : Peut ajouter
[Spring Boot] .down.&amp;amp;gt; [Search (ElasticSearch)] : Peut ajouter

[Supabase] .down.&amp;amp;gt; [PostgreSQL Replicas] : Peut ajouter

note bottom
  **Architecture extensible**
  Chaque ajout est indépendant
  Pas de refonte globale nécessaire
end note
@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_水平スケーリング&amp;quot;&amp;gt;水平スケーリング&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;アプリケーションが成長すると、ハイブリッドアーキテクチャは自然にスケールします：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;Supabase：&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;自動的に何百万件もの操作にスケールします&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;読み取りレプリカは読み取りパフォーマンス向上のために&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;ポイントインタイムリカバリ（セキュリティのため）&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;Spring Boot：&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;ロードバランサーの後ろの複数のインスタンス&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;ステートレス設計は水平スケーリングを容易にする&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;必要に応じてオーケストレーションにKubernetesを使用&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;PostgreSQL：&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;大規模テーブル向けのパーティショニング&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;接続プーリング (PgBouncer)&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;シャーディングが本当に必要な場合（まれ）&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_建築の証言&amp;quot;&amp;gt;建築の証言&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_スタートアップ_saas_50k_ユーザー&amp;quot;&amp;gt;スタートアップ SaaS (50k ユーザー)&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;em&amp;gt;&amp;lt;em&amp;gt;_ 私たちは100% Supabaseで始めました。 5,000ユーザーに達したとき、Stripeの請求処理と月次レポートのためにのみSpring Bootを追加しました。 1年後、私たちの運営の80%はまだSupabaseを通じて行われています。 Spring Bootは重要な部分のみを管理しています。 この分離により、リファクタリングなしでスケーリングすることができました。 &amp;lt;/em&amp;gt;_&amp;lt;/em&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_eラーニングプラットフォーム_10k_ユーザー&amp;quot;&amp;gt;Eラーニングプラットフォーム (10k ユーザー)&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;em&amp;gt;&amp;lt;em&amp;gt;_ SupabaseのOAuth2認証により、開発に3週間の短縮が実現しました。自動生成されたAPIがコースカタログ全体を管理します。Spring BootはPDF証明書と進捗メールにのみ使用されます。シンプルで保守性が高く、拡張性のあるアーキテクチャです。 &amp;lt;/em&amp;gt;_&amp;lt;/em&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_b2bマーケットプレイス_3kユーザー&amp;quot;&amp;gt;B2Bマーケットプレイス (3kユーザー)&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;em&amp;gt;&amp;lt;em&amp;gt;_ Spring Boot は買い手と売り手の間のトランザクションを管理します（重要）。Supabase はその他すべてを管理します：プロフィール、リアルタイムメッセージング、ドキュメント。同じ PostgreSQL データベースを共有しているため、複雑な同期を避けることができます。これまでで最良のアーキテクチャ選択でした。 &amp;lt;/em&amp;gt;_&amp;lt;/em&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_サマリーモダンな建築パラダイム&amp;quot;&amp;gt;サマリー：モダンな建築パラダイム&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;Supabase + Spring Boot のハイブリッドアーキテクチャは、新たなパラダイムを表しています：&amp;lt;strong&amp;gt;建�築の専門化&amp;lt;/strong&amp;gt;.&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
skinparam backgroundColor #FEFEFE

rectangle &amp;quot;旧パラダイム&amp;quot; #LightCoral {
  card &amp;quot;バックエンドのすべて&amp;quot; {
    [Auth]
    [CRUD]
    [Logique Métier]
    [Jobs]
    [Storage]
    [Realtime]
  }
  note bottom
    Complexité maximale
    dès le jour 1
  end note
}

rectangle &amp;quot;新しいパラダイム&amp;quot; #LightGreen {
  card &amp;quot;Supabase
(便利さ)&amp;quot; {
    [Auth]
    [CRUD Simple]
    [Storage]
    [Realtime]
  }

  card &amp;quot;Spring Boot
(差別化)&amp;quot; {
    [Logique Métier]
    [Jobs]
    [Intégrations]
  }

  note bottom
    Complexité progressive
    ajoutée seulement si nécessaire
  end note
}

[Ancien Paradigme] -right-&amp;amp;gt; [Nouveau Paradigme] : Évolution

@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;基本原理：&amp;lt;/strong&amp;gt;既にサービスとして存在するものを構築しないでください。 あなたのアプリケーションを差別化するものに焦点を当ててください。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_8020のルール&amp;quot;&amp;gt;80/20のルール&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;ほとんどのアプリケーション：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;80%の操作&amp;lt;/strong&amp;gt;は標準的なCRUDです → Supabase&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;20% の操作&amp;lt;/strong&amp;gt;ビジネスロジックが必要 → Spring Boot&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;この自然なルールは、ハイブリッドアーキテクチャを正当化する。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
skinparam backgroundColor #FEFEFE

package &amp;quot;操作の配分&amp;quot; {

  rectangle &amp;quot;80% - 標準作業&amp;quot; #LightGreen {
    [Lecture de données]
    [Création d&amp;#39;entités]
    [Mise à jour simple]
    [Suppression]
    [Upload fichiers]
    [Authentification]

    note bottom: **Géré par Supabase**
  }

  rectangle &amp;quot;20% - ビジネスロジック&amp;quot; #Coral {
    [Calculs complexes]
    [Workflows multi-étapes]
    [Transactions critiques]
    [Intégrations tierces]
    [Jobs planifiés]

    note bottom: **Géré par Spring Boot**
  }
}

note right
  **Focus optimal :**
  Votre temps de développement
  concentré sur les 20% qui
  différencient votre produit
end note
@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_最終的な結論&amp;quot;&amp;gt;最終的な結論&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;ハイブリッドアーキテクチャは技術的な妥協ではなく、それは&amp;lt;strong&amp;gt;戦略的な決定&amp;lt;/strong&amp;gt;.&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;これにより、あなたは以下のことができます：&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;�✅ 機能的なMVPで迅速に始める&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;�✅ 大規模な投資をせずに市場を検証する&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;�✅ 複雑さがそれを求めるとき、徐々に進化する&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;✅ 各ステップでコストをマスターする&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;�✅ 各テクノロジーの長所を活かす&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;過度な設計を早期に行わない&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;�✅ 将来のために柔軟性を保つ&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;彼女は表します :&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;�🎯&amp;lt;strong&amp;gt;実用主義&amp;lt;/strong&amp;gt;: 彼女が優れている各技術&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;�🚀&amp;lt;strong&amp;gt;速度&amp;lt;/strong&amp;gt;: 最小のタイム・トゥ・マーケット&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;金袋&amp;lt;strong&amp;gt;経済&amp;lt;/strong&amp;gt;: 価値に合わせたコスト&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;�🔮&amp;lt;strong&amp;gt;スケーラビリティ&amp;lt;/strong&amp;gt;あなたと共に成長するアーキテクチャ&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;🛡️&amp;lt;strong&amp;gt;�堅牢性&amp;lt;/strong&amp;gt;実証済みかつ信頼性の高いサービス&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_あなたの次の一歩&amp;quot;&amp;gt;あなたの次の一歩&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;このアーキテクチャが心に響くなら、始めるべき場所はこちらです：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;olist arabic&amp;quot;&amp;gt;
&amp;lt;ol class=&amp;quot;arabic&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;Supabaseのアカウントを作成してください&amp;lt;/strong&amp;gt;(無料)&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;最小のデータスキーマを設定してください&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;OAuth2 認証を設定してください&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;APIを消費する最初のJBakeページを作成してください&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;GitHub Pagesにデプロイ&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ol&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;機能的なMVPが手に入ります&amp;lt;strong&amp;gt;数日&amp;lt;/strong&amp;gt;.&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;Spring Boot は、必要になったときに自然とやってきます。それより前ではありません。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;hr&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;ハイブリッドアーキテクチャとは、必要なときに必要なものを正確に構築する芸術だ。&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;em&amp;gt;良い開発を！ 🚀&amp;lt;/em&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;hr&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;em&amp;gt;この記事を共有して、他の開発者が正しいアーキテクチャの選択をできるように手助けすると思う場合は。&amp;lt;/em&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;</description>
        </item><item>
            <title>プリロードの芸術：JavaScriptとCSSでテーマの「Flash」を消す</title>
            <link >https://cheroliv.com/blog/2025/0098_preloading_css_variable_post.html</link>
            <pubDate>Sat, 15 Nov 2025 00:00:00 +0000</pubDate>
            <guid isPermaLink="false">blog/2025/0098_preloading_css_variable_post.html</guid>
            <description>&amp;lt;div id=&amp;quot;toc&amp;quot; class=&amp;quot;toc&amp;quot;&amp;gt;
&amp;lt;div id=&amp;quot;toctitle&amp;quot;&amp;gt;Table des matières&amp;lt;/div&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel1&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_要約&amp;quot;&amp;gt;要約&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_問題_この呪われたテーマの点滅&amp;quot;&amp;gt;問題： この呪われたテーマの点滅&amp;lt;/a&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel2&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_ユーザーエクスペリエンスの悪夢&amp;quot;&amp;gt;ユーザーエクスペリエンスの悪夢&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_fouc古いウェブの問題&amp;quot;&amp;gt;FOUC：古いウェブの問題&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_品質の認識への影響&amp;quot;&amp;gt;品質の認識への影響&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_問題の技術的分析&amp;quot;&amp;gt;問題の技術的分析&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_なぜクラシックスクリプトでは十分ではないのですか&amp;quot;&amp;gt;なぜクラシックスクリプトでは十分ではないのですか？&amp;lt;/a&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel2&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_直感的だが非効率的なアプローチ&amp;quot;&amp;gt;直感的だが非効率的なアプローチ&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_domcontentloadedイベントを理解する&amp;quot;&amp;gt;DOMContentLoadedイベントを理解する&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_レンダーブロックの問題&amp;quot;&amp;gt;レンダーブロックの問題&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_問題の可視化&amp;quot;&amp;gt;問題の可視化&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_効果のない解決策の試み&amp;quot;&amp;gt;�効果のない解決策の試み&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_本当の解決策もっと早く行動する&amp;quot;&amp;gt;本当の解決策：もっと早く行動する&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_ソリューション_早期読み込み_early_loading&amp;quot;&amp;gt;ソリューション: 早期読み込み (Early Loading)&amp;lt;/a&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel2&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_基本原理&amp;quot;&amp;gt;基本原理&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_なぜheadが理想的な場所なのか&amp;quot;&amp;gt;なぜ`&amp;amp;lt;head&amp;amp;gt;`が理想的な場所なのか&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_ソリューションの3層アーキテクチャ&amp;quot;&amp;gt;ソリューションの3層アーキテクチャ&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_ステップ1ユーザーの選択を保存する&amp;quot;&amp;gt;ステップ1：ユーザーの選択を保存する&amp;lt;/a&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel2&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_localstorage_あなたの永続的なメモリ&amp;quot;&amp;gt;localStorage: あなたの永続的なメモリ&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_テーマバックアップの実装&amp;quot;&amp;gt;テーマバックアップの実装&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_エラーケースの管理&amp;quot;&amp;gt;エラーケースの管理&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_高度な永続性の戦略&amp;quot;&amp;gt;高度な永続性の戦略&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_ステップ2head内のプレロードスクリプト&amp;quot;&amp;gt;ステップ2：`&amp;amp;lt;head&amp;amp;gt;`内のプレロードスクリプト&amp;lt;/a&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel2&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_解決策の中心&amp;quot;&amp;gt;解決策の中心&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_スクリプトの解剖各行が重要&amp;quot;&amp;gt;スクリプトの解剖：各行が重要&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_システム設定の検出_ボーナス&amp;quot;&amp;gt;システム設定の検出 (ボーナス)&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_パフォーマンスなぜこのスクリプトは速い&amp;quot;&amp;gt;パフォーマンス：なぜこのスクリプトは速い&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_head内の最適な配置&amp;quot;&amp;gt;&amp;amp;lt;head&amp;amp;gt;内の最適な配置&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_ステップ3_css属性セレクタの力&amp;quot;&amp;gt;ステップ3: CSS属性セレクタの力&amp;lt;/a&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel2&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_bootstrap_5_のテーマシステム&amp;quot;&amp;gt;Bootstrap 5 のテーマシステム&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_テーマシステム用のcss構造&amp;quot;&amp;gt;テーマシステム用のCSS構造&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_要約&amp;quot;&amp;gt;要約&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;この詳細な技術記事では、ページの読み込み時に発生する不快なちらつきを伴わないテーマセレクター（light/dark）の実装方法を探ります。ブラウザのレンダリングサイクルを詳しく分析し、FOUC（Flash of Unstyled Content）の根本原因を明らかにし、同期プリロードに基づく堅牢なソリューションの`&amp;amp;lt;head&amp;amp;gt;`この技術は、スムーズでプロフェッショナルなユーザー体験を保証します。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_問題_この呪われたテーマの点滅&amp;quot;&amp;gt;問題： この呪われたテーマの点滅&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_ユーザーエクスペリエンスの悪夢&amp;quot;&amp;gt;ユーザーエクスペリエンスの悪夢&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;想像してください：あなたはウェブアプリ用の素晴らしいダークテーマを作るのに何時間も費やしました。色は完璧にバランスが取れ、コントラストは最適で、ユーザーはこのオプションを愛しています。しかし、恥ずかしげな問題があります：ページをリロードするたびに、一瞬だけデフォルトのライトテーマが表示され、それからダークテーマに切り替わります。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;このビジュアルな&amp;quot;flash&amp;quot;は、短い（時には100ms未満）にもかかわらず、人間の目にすぐに感じ取られ、不快な体験を作り出します。視覚的な快適さやアクセシビリティのためにダークテーマを選択したユーザーにとって、このちらつきは場合によって痛みを感じるほどになり得ます。特に照明が薄い環境ではそうなります。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_fouc古いウェブの問題&amp;quot;&amp;gt;FOUC：古いウェブの問題&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;この現象は「Flash of Unstyled Content」（FOUC）と呼ばれるものの一種であり、これはウェブ開発における古典的な問題で、CSSの黎明期まで遡ります。FOUCは、ブラウザが一時的にCSSが適用されていないHTMLコンテンツを表示し、スタイルの適用されていないコンテンツのフラッシュを引き起こすときに発生します。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;私たちの特殊なケースでは、完全にスタイルが適用されていないコンテンツではなく、むしろ&amp;lt;strong&amp;gt;間違ったテーマのフラッシュ&amp;lt;/strong&amp;gt;(FOWT) - 内容はスタイルされているが、間違ったテーマが適用されている。特にイライラするのは、ページを読み込むたびにアプリがユーザーの好みを「忘れて」しまうことを示しているからだ。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_品質の認識への影響&amp;quot;&amp;gt;品質の認識への影響&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;この問題は技術的なものですが、アプリケーションの品質に対する認識に重大な影響を与えます。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;ポリッシュ不足&amp;lt;/strong&amp;gt;: 点滅は、未完成あるいは最適化されていないアプリケーションであるという印象を与えます。ユーザーはしばしばこれらの小さな視覚的な欠陥を、プロフェッショナリズム全般の欠如と関連付けます。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;一貫性の欠如&amp;lt;/strong&amp;gt;アプリケーションはユーザーの設定を「忘れている」ように見え、インターフェイスと期待の間にずれている感覚を作り出します。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;視覚疲労&amp;lt;/strong&amp;gt;光に敏感なユーザーや片頭痛に苦しむユーザーにとって、この明るいフラッシュは単なる見た目の不快感以上の問題となる可能性があります。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;知覚されたパフォーマンス&amp;lt;/strong&amp;gt;皮肉にも、サイトがすぐに読み込まれても、この点滅は遅い、または応答性の低いアプリケーションのように感じられることがあります。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_問題の技術的分析&amp;quot;&amp;gt;問題の技術的分析&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;この問題を解決する方法を理解するには、まずなぜそれが起こるのかを理解する必要があります。ウェブページのライフサイクルにおける3つのクリティカルなイベント間の時間的ずれによって、ちらつきが発生します。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;olist arabic&amp;quot;&amp;gt;
&amp;lt;ol class=&amp;quot;arabic&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;HTMLの初期パース&amp;lt;/strong&amp;gt;ブラウザはページの構造を読み込み、分析します&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;CSSスタイルの適用&amp;lt;/strong&amp;gt;ブラウザはCSSのルールを適用し、視覚的レンダリングを計算します。&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;JavaScriptの実行&amp;lt;/strong&amp;gt;: テーマを変更するコードが実行されます&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ol&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;問題は、イベント n°3 (JavaScript の実行) が、ブラウザがすでに開始または完了したイベント n°2 (スタイルの適用) の後に到着するときに起こります。その時点では、ブラウザはどのテーマを表示するかを既に決定しており、あなたのコードは最初のレンダリング前にそれを影響するには遅すぎます。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_なぜクラシックスクリプトでは十分ではないのですか&amp;quot;&amp;gt;なぜクラシックスクリプトでは十分ではないのですか？&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_直感的だが非効率的なアプローチ&amp;quot;&amp;gt;直感的だが非効率的なアプローチ&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;開発者にとって最も自然なアプローチは、スクリプトを私たちの最後尾に配置すること`&amp;amp;lt;body&amp;amp;gt;`ユーザーの好みのテーマをチェックして適用する。このアプローチは、レンダリングをブロックしないようにページの最後にスクリプトを読み込むことを推奨する従来のウェブベストプラクティスに従う。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-javascript hljs&amp;quot; data-lang=&amp;quot;javascript&amp;quot;&amp;gt;// À la fin de &amp;amp;lt;body&amp;amp;gt; - L&amp;#39;APPROCHE INSUFFISANTE
document.addEventListener(&amp;#39;DOMContentLoaded&amp;#39;, () =&amp;amp;gt; {
  const theme = localStorage.getItem(&amp;#39;preferred-theme&amp;#39;);
  if (theme === &amp;#39;dark&amp;#39;) {
    document.documentElement.setAttribute(&amp;#39;data-bs-theme&amp;#39;, &amp;#39;dark&amp;#39;);
  }
});&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;このアプローチは一見論理的に見える。DOMが準備できるのを待ってから、テーマを適用する。シンプルだろう？残念ながら、このシンプルさはブラウザのレンダリングサイクルのタイミングに関連する根本的な欠陥を隠している。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_domcontentloadedイベントを理解する&amp;quot;&amp;gt;DOMContentLoadedイベントを理解する&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;イベント`DOMContentLoaded`初期のHTMLドキュメントがブラウザによって完全に読み込まれ、解析されたときにトリガーされます,&amp;lt;strong&amp;gt;待たずに&amp;lt;/strong&amp;gt;スタイルシート、画像、サブフレームの読み込みの終了。 これは理解すべき重要な点です。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;これが典型的なイベントのシーケンスです：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;olist arabic&amp;quot;&amp;gt;
&amp;lt;ol class=&amp;quot;arabic&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;ブラウザはHTMLのダウンロードを開始します&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;彼は受信されるHTMLを逐次分析する&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;彼はタグを見つける`&amp;amp;lt;link&amp;amp;gt;`CSS用にダウンロードを開始する&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;彼はタグを見つける`&amp;amp;lt;script&amp;amp;gt;`それらを（その種類および属性に応じて）実行します&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;彼は DOM (Document Object Model) を構築します。&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;イベント &amp;lt;code&amp;gt;DOMContentLoaded&amp;lt;/code&amp;gt; がトリガーされます&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;彼はスタイルを適用し続け、レイアウトを作成し続けている&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;最初のペイント（表示）が発生します&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;イベント`load`すべてのリソースが読み込まれたときに発動します&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ol&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;問題は？ステップ6（DOMContentLoaded）とステップ8（最初のペイント）の間で、ブラウザはすでにページの表示方法について決定を下しています。テーマ変更スクリプトがステップ6で実行される場合、デフォルトのスタイルでの最初の表示を避けるにはすでに遅すぎます。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_レンダーブロックの問題&amp;quot;&amp;gt;レンダーブロックの問題&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;実際、タイミングはさらに複雑です。モダンなブラウザーは、知覚されるパフォーマンスを向上させるため、高度な最適化技術を使用しています。彼らは、ユーザーが画面上で何かを見られるように、最初のペイント（First Contentful Paint）をできるだけ早く行おうとします。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;CSSはデフォルトで&amp;quot;render-blocking&amp;quot;であり、これはブラウザがスタイルシートをダウンロードして解析するまで最初のペイントを行わないことを意味します。これは理にかなっています：スタイルが適用されていないコンテンツを表示したくないからです。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;しかし、ここに落とし穴があります：ブラウザがこれらのCSSスタイルを初めて適用するとき、それは現在のDOMの状態に基づいて行われます。もし属性が`data-bs-theme`まだタグに定義されていません`&amp;amp;lt;html&amp;amp;gt;`, ブラウザはデフォルトのスタイルを適用します（通常はライトテーマ）。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;次に、スクリプトが実行され、この属性が変更されたとき、ブラウザは：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;olist arabic&amp;quot;&amp;gt;
&amp;lt;ol class=&amp;quot;arabic&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;この変更に影響を受けるすべてのスタイルを再計算してください&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;必要に応じてレイアウトをやり直す&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;影響を受けた要素を塗り直す&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ol&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;この再計算と再塗装のプロセスが、可視的な点滅を引き起こすものです。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_問題の可視化&amp;quot;&amp;gt;問題の可視化&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;この問題のあるシーケンスをよりよく理解するために、詳細なシーケンス図を検討しましょう：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div id=&amp;quot;diag-flux-incorrect&amp;quot; class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
actor Utilisateur
participant Navigateur
participant &amp;quot;HTMLパーサー&amp;quot; as Parser
participant &amp;quot;CSSOM&amp;quot; as CSS
participant &amp;quot;Script.js (ボディの終わり)&amp;quot; as Script
participant &amp;quot;レンダーエンジン&amp;quot; as Render

Utilisateur -&amp;amp;gt; Navigateur: Demande la page
activate Navigateur

Navigateur -&amp;amp;gt; Parser: Parse le HTML
activate Parser
Parser -&amp;amp;gt; CSS: Découvre et charge les CSS
activate CSS
Parser -&amp;amp;gt; Parser: Construit le DOM
Parser -&amp;amp;gt; Navigateur: DOM Ready (DOMContentLoaded)
deactivate Parser

CSS -&amp;amp;gt; CSS: Parse les feuilles de style
CSS -&amp;amp;gt; Render: CSSOM Ready
deactivate CSS

activate Render
Render -&amp;amp;gt; Render: Calcule les styles avec data-bs-theme=&amp;quot;&amp;quot;note right: デフォルトテーマ (light)
Render -&amp;amp;gt; Navigateur: 初回ペイント (ライトテーマ)
note right: ユーザーはライトテーマを見ます
deactivate Render

Navigateur -&amp;amp;gt; Script: スクリプトを実行
activate Script
Script -&amp;amp;gt; Script: localStorageを読む
Script -&amp;amp;gt; Navigateur: setAttribute(&amp;#39;data-bs-theme&amp;#39;, &amp;#39;dark&amp;#39;)
deactivate Script

activate Render
Render -&amp;amp;gt; Render: data-bs-themeを含むスタイルを再計算&amp;quot;dark&amp;quot;
note right: Thème sombre
Render -&amp;amp;gt; Navigateur: Repaint (Thème Sombre)
note right: Clignotement visible
deactivate Render

deactivate Navigateur
@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;この図は問題をはっきりと示しています：最初のペイントは、スクリプトが正しいテーマを設定する機会を得る前に発生します。その後のリペイントが目に見えるちらつきを引き起こします。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_効果のない解決策の試み&amp;quot;&amp;gt;�効果のない解決策の試み&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;この問題を解決しようといくつかのアプローチが試みられましたが、ほとんどのものはそれぞれ固有の欠点があります：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;方法1：読み込み完了までコンテンツを隠す&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-css hljs&amp;quot; data-lang=&amp;quot;css&amp;quot;&amp;gt;body {
  opacity: 0;
  transition: opacity 0.3s;
}

body.loaded {
  opacity: 1;
}&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;このアプローチは、JavaScriptが正しいテーマを設定するまで、すべてのコンテンツを隠します。問題点は？これは人工的にコンテンツの表示を遅らせ、サイトが遅く感じられる印象を与えます。さらに、JavaScriptが無効になっている場合、ユーザーは何も見ることができません！&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;アプローチ 2：ローダー/スピナーを使用する&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;アプローチ 1 と同様ですが、ローディングスピナーがあります。これは問題を隠すだけで、実際のパフォーマンスは改善せず、無駄な知覚的な遅延を追加します。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;アプローチ3：暗いテーマをデフォルトにする&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;一部の開発者はCSSでダークテーマをデフォルトに設定します。これにより、ダークテーマユーザーのちらつきは防げますが、ライトテーマユーザーには逆に問題が発生します！&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;これらのアプローチのいずれも満足できるものではなく、問題の根本原因ではなく症状に対処しているからです。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_本当の解決策もっと早く行動する&amp;quot;&amp;gt;本当の解決策：もっと早く行動する&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;この問題を解決する鍵は、属性を設定する必要があることに気づくことです`data-bs-theme` &amp;lt;strong&amp;gt;前&amp;lt;/strong&amp;gt;ブラウザがCSSスタイルを適用し始める前に。これは、私たちのスクリプトがページのライフサイクルの中でより早く実行される必要があることを意味します。そして、これは次のセクションで探求するまさにそれです。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_ソリューション_早期読み込み_early_loading&amp;quot;&amp;gt;ソリューション: 早期読み込み (Early Loading)&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_基本原理&amp;quot;&amp;gt;基本原理&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;私たちの点滅問題のエレガントな解決策は、シンプルだが強力な原理に基づいています：&amp;lt;strong&amp;gt;アプリケーションの状態をブラウザのレンダリングプロセスと同期する&amp;lt;/strong&amp;gt;.代わりに、ページが読み込まれるのを待ってテーマを設定するのではなく、テーマを設定する必要があります。&amp;lt;strong&amp;gt;の間に&amp;lt;/strong&amp;gt;読み込み、CSSスタイルが適用される前でも&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;このアプローチは、ウェブ開発の用語で「Early Loading」または「Synchronous Preloading」と呼ばれます。このアイデアは、ページのライフサイクルにおいて可能な限り早くテーマ検出ロジックを実行し、理想的にはタグ内で行うことです。&amp;lt;code&amp;gt;&amp;amp;lt;head&amp;amp;gt;&amp;lt;/code&amp;gt;, ブラウザが CSS ファイルのダウンロードを開始するよりも前に&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_なぜheadが理想的な場所なのか&amp;quot;&amp;gt;なぜ`&amp;amp;lt;head&amp;amp;gt;`が理想的な場所なのか&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;Le `&amp;amp;lt;head&amp;amp;gt;`HTMLドキュメントはブラウザによって上から下へと順に処理されます。各要素は表示される順序で処理されます。この特性は私たちのソリューションにとって重要です。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;ブラウザがタグに遭遇するとき`&amp;amp;lt;script&amp;amp;gt;`中の`&amp;amp;lt;head&amp;amp;gt;`属性なし`async` ou &amp;lt;code&amp;gt;defer&amp;lt;/code&amp;gt;, il :&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;olist arabic&amp;quot;&amp;gt;
&amp;lt;ol class=&amp;quot;arabic&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;HTML のパースを中断する&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;スクリプトをダウンロード&amp;lt;/strong&amp;gt;(外部の場合)またはベッド(インラインの場合)&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;すぐにスクリプトを実行して&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;HTMLのパースを再開する&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ol&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;この動作は、しばしばパフォーマンスの問題と見なされる（そのため、ページの最後にスクリプトを配置するという通常の推奨がある）が、この場合は私たちの味方となる。私たちのテーマ検出スクリプトをページの先頭に`&amp;amp;lt;head&amp;amp;gt;`, 私たちはそれがブラウザーがタグに出会う前に実行されることを保証します`&amp;amp;lt;link&amp;amp;gt;`私たちのスタイルシートの。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_ソリューションの3層アーキテクチャ&amp;quot;&amp;gt;ソリューションの3層アーキテクチャ&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;私たちの完全なソリューションは、相互に依存する3つの層から構成されており、それぞれが特定の役割を果たします：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;層 1 : 永続性 (localStorage)&amp;lt;/strong&amp;gt; この層は、セッション間でユーザーの選択を保存および取得する役割を担っています。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;レイヤー 2: 早期同期（`&amp;amp;lt;head&amp;amp;gt;`内のインラインスクリプト）&amp;lt;/strong&amp;gt; このレイヤーは、初期レンダリング前にアプリケーションの状態とDOMを同期します。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;レイヤー3:レスポンシブスタイル (属性セレクタを使ったCSS)&amp;lt;/strong&amp;gt; このレイヤーは、レイヤー2で定義された状態に基づいてビジュアルスタイルを定義します。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;それでは、各層を詳細に調べていきましょう。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_ステップ1ユーザーの選択を保存する&amp;quot;&amp;gt;ステップ1：ユーザーの選択を保存する&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_localstorage_あなたの永続的なメモリ&amp;quot;&amp;gt;localStorage: あなたの永続的なメモリ&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;Le &amp;lt;code&amp;gt;localStorage`は、ブラウザにキーと値のペアを永続的に保存できる Web Storage API です。 Cookie とは異なり、データは`localStorage&amp;lt;/code&amp;gt; :&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;サーバーには決して自動的に送信されません&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;ストレージ容量が大きい（通常は5-10MB）&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;有効期限がなく（明示的に削除されるまで継続）&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;プロトコルとドメインに制限されます (Same-Origin Policy)&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;私たちのユースケースでは、`localStorage`完璧です。なぜなら：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;olist arabic&amp;quot;&amp;gt;
&amp;lt;ol class=&amp;quot;arabic&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;私たちはこの情報をサーバーと共有する必要はありません&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;私たちが望むのは、その好みが永遠に続くことです。&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;必要なストレージサイズは最小限です (数バイト)&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ol&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_テーマバックアップの実装&amp;quot;&amp;gt;テーマバックアップの実装&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;ユーザーがテーマを変更するときの選択を保存する方法は次の通りです：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-javascript hljs&amp;quot; data-lang=&amp;quot;javascript&amp;quot;&amp;gt;// Fonction complète pour changer le thème
function setTheme(newTheme) {
  // Validation de l&amp;#39;entrée
  if (![&amp;#39;light&amp;#39;, &amp;#39;dark&amp;#39;, &amp;#39;auto&amp;#39;].includes(newTheme)) {
    console.error(&amp;#39;Thème invalide:&amp;#39;, newTheme);
    return;
  }

  try {
    // Sauvegarde dans localStorage
    localStorage.setItem(&amp;#39;preferred-theme&amp;#39;, newTheme);

    // Application immédiate dans le DOM
    document.documentElement.setAttribute(&amp;#39;data-bs-theme&amp;#39;, newTheme);

    // Dispatch d&amp;#39;un événement personnalisé pour notifier d&amp;#39;autres composants
    window.dispatchEvent(new CustomEvent(&amp;#39;theme-changed&amp;#39;, {
      detail: { theme: newTheme }
    }));

    console.log(&amp;#39;Thème changé:&amp;#39;, newTheme);
  } catch (error) {
    console.error(&amp;#39;Erreur lors de la sauvegarde du thème:&amp;#39;, error);
    // Fallback : on applique quand même le thème visuellement
    document.documentElement.setAttribute(&amp;#39;data-bs-theme&amp;#39;, newTheme);
  }
}

// Exemple d&amp;#39;utilisation avec un bouton
document.getElementById(&amp;#39;theme-toggle&amp;#39;).addEventListener(&amp;#39;click&amp;#39;, () =&amp;amp;gt; {
  const currentTheme = document.documentElement.getAttribute(&amp;#39;data-bs-theme&amp;#39;) || &amp;#39;light&amp;#39;;
  const newTheme = currentTheme === &amp;#39;light&amp;#39; ? &amp;#39;dark&amp;#39; : &amp;#39;light&amp;#39;;
  setTheme(newTheme);
});&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_エラーケースの管理&amp;quot;&amp;gt;エラーケースの管理&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;レのケースを処理することは重要です`localStorage`利用できないか、アクセスできない可能性があります。いくつかのシナリオがへのアクセスを妨げる可能性があります`localStorage`(No content to translate, so output nothing.)&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;�厳格なプライベートナビゲーション&amp;lt;/strong&amp;gt;: Safariのプライベートブラウジングモードで例外が発生します`QuotaExceededError`書き込みを試みる際の`localStorage`.&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;プライバシー設定&amp;lt;/strong&amp;gt;一部のブラウザまたはプライバシー拡張機能は、アクセスをブロックする可能性があります`localStorage`。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;ドメインの制限&amp;lt;/strong&amp;gt; : Le `localStorage`プロトコル上ではアクセスできません`file://`一部のブラウザでは。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;ストレージの容量がいっぱいです&amp;lt;/strong&amp;gt;稀ではありますが、ストレージスペースは完全に満たされることがあります。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;それが、私たちのコードがブロックを使用する理由です。`try&amp;amp;#8230;&amp;amp;#8203;catch`これらのケースを優雅に処理し、永続性が利用できない場合でもテーマ変更機能を提供し続ける&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_高度な永続性の戦略&amp;quot;&amp;gt;高度な永続性の戦略&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;より高度なアプリケーションの場合、追加の戦略を検討することができます：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;サーバー同期（オプション）&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-javascript hljs&amp;quot; data-lang=&amp;quot;javascript&amp;quot;&amp;gt;async function setTheme(newTheme) {
  // Sauvegarde locale immédiate
  localStorage.setItem(&amp;#39;preferred-theme&amp;#39;, newTheme);
  document.documentElement.setAttribute(&amp;#39;data-bs-theme&amp;#39;, newTheme);

  // Synchronisation serveur en arrière-plan (si l&amp;#39;utilisateur est connecté)
  if (userIsAuthenticated()) {
    try {
      await fetch(&amp;#39;/api/user/preferences&amp;#39;, {
        method: &amp;#39;POST&amp;#39;,
        headers: { &amp;#39;Content-Type&amp;#39;: &amp;#39;application/json&amp;#39; },
        body: JSON.stringify({ theme: newTheme })
      });
    } catch (error) {
      console.warn(&amp;#39;Échec de la synchronisation serveur:&amp;#39;, error);
      // L&amp;#39;échec n&amp;#39;est pas critique car la préférence est déjà sauvegardée localement
    }
  }
}&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;このアプローチは、接続されているユーザーの好みをデバイス間で同期し、同時に即時のローカル応答性を維持します。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_ステップ2head内のプレロードスクリプト&amp;quot;&amp;gt;ステップ2：`&amp;amp;lt;head&amp;amp;gt;`内のプレロードスクリプト&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_解決策の中心&amp;quot;&amp;gt;解決策の中心&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;ここで魔法が本当に働きます。私たちは小さなスクリプトを配置するつもりです。&amp;lt;strong&amp;gt;インライン&amp;lt;/strong&amp;gt;直接私たちの`&amp;amp;lt;head&amp;amp;gt;`, すべてのタグの前に`&amp;amp;lt;link&amp;amp;gt;`スタイルシートの。このスクリプトは意図的にミニマルで、自立しており、できるだけ早く実行されるように設計されています。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-html hljs&amp;quot; data-lang=&amp;quot;html&amp;quot;&amp;gt;&amp;amp;lt;!DOCTYPE html&amp;amp;gt;
&amp;amp;lt;html lang=&amp;quot;fr&amp;quot;&amp;amp;gt;
&amp;amp;lt;head&amp;amp;gt;
    &amp;amp;lt;meta charset=&amp;quot;UTF-8&amp;quot;&amp;amp;gt;
    &amp;amp;lt;meta name=&amp;quot;viewport&amp;quot; content=&amp;quot;width=device-width, initial-scale=1.0&amp;quot;&amp;amp;gt;
    &amp;amp;lt;title&amp;amp;gt;Mon Site Incroyable&amp;amp;lt;/title&amp;amp;gt;

    &amp;amp;lt;!-- ==========================================
         NOTRE SCRIPT MAGIQUE DE PRÉ-CHARGEMENT
         Ce script DOIT être le premier élément
         dans le &amp;amp;lt;head&amp;amp;gt; après les meta tags
         ========================================== --&amp;amp;gt;
    &amp;amp;lt;script&amp;amp;gt;
      // IIFE pour ne pas polluer le scope global
      (function() {
        &amp;#39;use strict&amp;#39;;

        try {
          // Lecture de la préférence sauvegardée
          const savedTheme = localStorage.getItem(&amp;#39;preferred-theme&amp;#39;);

          // Si une préférence existe, on l&amp;#39;applique immédiatement
          if (savedTheme) {
            document.documentElement.setAttribute(&amp;#39;data-bs-theme&amp;#39;, savedTheme);
          }
          // Optionnel : Détecter la préférence système si aucune sauvegarde
          else if (window.matchMedia &amp;amp;amp;&amp;amp;amp; window.matchMedia(&amp;#39;(prefers-color-scheme: dark)&amp;#39;).matches) {
            document.documentElement.setAttribute(&amp;#39;data-bs-theme&amp;#39;, &amp;#39;dark&amp;#39;);
          }
          // Sinon, le thème par défaut du CSS sera utilisé (généralement &amp;#39;light&amp;#39;)

        } catch (error) {
          // En cas d&amp;#39;erreur (localStorage bloqué, etc.), on log discrètement
          // et on laisse le thème par défaut s&amp;#39;appliquer
          console.warn(&amp;#39;Impossible de charger la préférence de thème:&amp;#39;, error);
        }
      })();
    &amp;amp;lt;/script&amp;amp;gt;
    &amp;amp;lt;!-- FIN DU SCRIPT MAGIQUE --&amp;amp;gt;

    &amp;amp;lt;!-- Les feuilles de style sont chargées APRÈS le script --&amp;amp;gt;
    &amp;amp;lt;link rel=&amp;quot;stylesheet&amp;quot; href=&amp;quot;css/bootstrap.min.css&amp;quot;&amp;amp;gt;
    &amp;amp;lt;link rel=&amp;quot;stylesheet&amp;quot; href=&amp;quot;css/styles.css&amp;quot;&amp;amp;gt;

    &amp;amp;lt;!-- Autres ressources du head --&amp;amp;gt;
    &amp;amp;lt;link rel=&amp;quot;icon&amp;quot; href=&amp;quot;favicon.ico&amp;quot;&amp;amp;gt;
&amp;amp;lt;/head&amp;amp;gt;
&amp;amp;lt;body&amp;amp;gt;
    &amp;amp;lt;!-- Contenu de la page --&amp;amp;gt;
&amp;amp;lt;/body&amp;amp;gt;
&amp;amp;lt;/html&amp;amp;gt;&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_スクリプトの解剖各行が重要&amp;quot;&amp;gt;スクリプトの解剖：各行が重要&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;このスクリプトを一行ずつ分解して、各設計上の決定を理解しましょう：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;IIFE（即時実行関数式）&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-javascript hljs&amp;quot; data-lang=&amp;quot;javascript&amp;quot;&amp;gt;(function() {
  // ...
})();&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;この構造は即時実行される関数を作成します。なぜ？ローカルスコープで変数を隔離し、グローバルスコープを汚染しないようにするためです。たとえ私たちが使っているのはこれだけでも`const`(ブロックスコープを持つ), IIFEは良いプラクティスであり、私たちの意図を明確にし、名前の衝突から保護します。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;Strictモード&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-javascript hljs&amp;quot; data-lang=&amp;quot;javascript&amp;quot;&amp;gt;&amp;#39;use strict&amp;#39;;&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;このディレクティブは JavaScript の厳格モードを有効にし、： - 未宣言の変数の使用を禁止する - 危険な操作に対してエラーを生成する - 一部のJavaScriptエンジンでパフォーマンスが向上します&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;重要なスクリプトの場合、最大限のセキュリティが必要です。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;try&amp;amp;#8230;&amp;amp;#8203;catch ブロック&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-javascript hljs&amp;quot; data-lang=&amp;quot;javascript&amp;quot;&amp;gt;try {
  // Code principal
} catch (error) {
  console.warn(&amp;#39;Impossible de charger la préférence de thème:&amp;#39;, error);
}&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;このブロックは絶対に重要です。これは、localStorage がブロックされたり、考えにくい構文エラーが発生したりなど、何らかの問題が発生しても、スクリプトがページ全体の読み込みを妨げないことを保証します。使用する`console.warn`むしろ`console.error`これは重大でない問題であることを示します。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;localStorageの読み取り&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-javascript hljs&amp;quot; data-lang=&amp;quot;javascript&amp;quot;&amp;gt;const savedTheme = localStorage.getItem(&amp;#39;preferred-theme&amp;#39;);&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;この行は特定のコンテキスト（Safariの厳格なプライベートブラウジング）で例外をスローする可能性があるため、try&amp;amp;#8230;&amp;amp;#8203;catch ブロック内に置かれています。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;条件付きアプリケーション&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-javascript hljs&amp;quot; data-lang=&amp;quot;javascript&amp;quot;&amp;gt;if (savedTheme) {
  document.documentElement.setAttribute(&amp;#39;data-bs-theme&amp;#39;, savedTheme);
}&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;保存されたテーマを見つけた場合のみ、そのテーマを適用します。そうでない場合は、CSSがデフォルトのテーマを使用するようにします。このアプローチは、JavaScriptにハードコーディングされたデフォルト値よりも堅牢です。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_システム設定の検出_ボーナス&amp;quot;&amp;gt;システム設定の検出 (ボーナス)&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;オプションだがエレガントな改善は、ユーザーがまだアプリ内で明示的な選択をしていない場合、オペレーティングシステムのテーマ設定を検出することです:&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-javascript hljs&amp;quot; data-lang=&amp;quot;javascript&amp;quot;&amp;gt;else if (window.matchMedia &amp;amp;amp;&amp;amp;amp; window.matchMedia(&amp;#39;(prefers-color-scheme: dark)&amp;#39;).matches) {
  document.documentElement.setAttribute(&amp;#39;data-bs-theme&amp;#39;, &amp;#39;dark&amp;#39;);
}&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;この機能はメディアクエリを使います`prefers-color-scheme`システムを問い合わせるため。macOS、Windows 10+、iOS、および最新のAndroidでは、このクエリはユーザーのシステム設定を返します。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;利点：&amp;lt;/strong&amp;gt; 初めての訪問からのパーソナライズドな体験 - ユーザーのシステム環境との整合性 - 初回訪問にストレージは必要ありません&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;考慮事項 :&amp;lt;/strong&amp;gt; - すべてのブラウザーがこの機能をサポートしているわけではない（ただし、2020年以降サポートは非常に優れている） - 検証`window.matchMedia`互換性を確保する - ユーザーは常にこの選択を上書きできます&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_パフォーマンスなぜこのスクリプトは速い&amp;quot;&amp;gt;パフォーマンス：なぜこのスクリプトは速い&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;私たちのプリロードスクリプトは、非常に高速に動作するように設計されています：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;最小サイズ&amp;lt;/strong&amp;gt;約300バイト（未圧縮）、200バイト（圧縮後）。これは、どの画像やJavaScriptライブラリに比べても無視できる程度です。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;インライン&amp;lt;/strong&amp;gt;追加の HTTP リクエストはありません。スクリプトは HTML に組み込まれているため、すぐに利用できます。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;シンプルな同期操作&amp;lt;/strong&amp;gt;localStorageからキーを読み取る（超高速な操作）と、DOM属性を変更する（ブラウザのネイティブな操作）.&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;依存関係なし&amp;lt;/strong&amp;gt;: フレームワークもライブラリもなく、ただのバニラJavaScriptだけ。起動時間も依存のパースもなし。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;一度だけの実行&amp;lt;/strong&amp;gt;: このスクリプトはロード時に1回だけ実行されます。イベントリスナーもループも複雑な計算もありません。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;実際に、最新のハードウェアでは、このスクリプトは1ミリ秒未満で実行され、ページの読み込みパフォーマンスに影響を与えないほどの無視できる時間です。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_head内の最適な配置&amp;quot;&amp;gt;&amp;amp;lt;head&amp;amp;gt;内の最適な配置&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;要素の順序は`&amp;amp;lt;head&amp;amp;gt;`重要です。おすすめの順序は次のとおりです：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-html hljs&amp;quot; data-lang=&amp;quot;html&amp;quot;&amp;gt;&amp;amp;lt;head&amp;amp;gt;
    &amp;amp;lt;!-- 1. Métadonnées critiques --&amp;amp;gt;
    &amp;amp;lt;meta charset=&amp;quot;UTF-8&amp;quot;&amp;amp;gt;
    &amp;amp;lt;meta name=&amp;quot;viewport&amp;quot; content=&amp;quot;width=device-width, initial-scale=1.0&amp;quot;&amp;amp;gt;

    &amp;amp;lt;!-- 2. Notre script de pré-chargement (IMMÉDIATEMENT après les meta) --&amp;amp;gt;
    &amp;amp;lt;script&amp;amp;gt;
      (function() { /* notre code */ })();
    &amp;amp;lt;/script&amp;amp;gt;

    &amp;amp;lt;!-- 3. Titre de la page --&amp;amp;gt;
    &amp;amp;lt;title&amp;amp;gt;Mon Site&amp;amp;lt;/title&amp;amp;gt;

    &amp;amp;lt;!-- 4. Feuilles de style --&amp;amp;gt;
    &amp;amp;lt;link rel=&amp;quot;stylesheet&amp;quot; href=&amp;quot;styles.css&amp;quot;&amp;amp;gt;

    &amp;amp;lt;!-- 5. Autres ressources (fonts, favicons, etc.) --&amp;amp;gt;
    &amp;amp;lt;link rel=&amp;quot;preconnect&amp;quot; href=&amp;quot;https://fonts.googleapis.com&amp;quot;&amp;amp;gt;
    &amp;amp;lt;link rel=&amp;quot;icon&amp;quot; href=&amp;quot;favicon.ico&amp;quot;&amp;amp;gt;

    &amp;amp;lt;!-- 6. Autres scripts avec defer ou async --&amp;amp;gt;
    &amp;amp;lt;script src=&amp;quot;app.js&amp;quot; defer&amp;amp;gt;&amp;amp;lt;/script&amp;amp;gt;
&amp;amp;lt;/head&amp;amp;gt;&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;この注文は次のことを保証します：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;olist arabic&amp;quot;&amp;gt;
&amp;lt;ol class=&amp;quot;arabic&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;charsetはテキスト処理の前に定義される&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;私たちのスクリプトはCSSの読み込み前に実行されます&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;CSSはその後読み込まれ、正しいテーマを直接適用します。&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;その他の非クリティカルなリソースは最後に読み込まれます&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ol&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_ステップ3_css属性セレクタの力&amp;quot;&amp;gt;ステップ3: CSS属性セレクタの力&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_bootstrap_5_のテーマシステム&amp;quot;&amp;gt;Bootstrap 5 のテーマシステム&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;Bootstrap 5はCSSカスタムプロパティ（CSS変数）および属性セレクターに基づいたエレガントなテーマ管理システムを導入しました。このシステムは属性`data-bs-theme`要素の上に`&amp;amp;lt;html&amp;amp;gt;`どの色変数のセットを適用するかを決定するために。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;このシステムの美しさはそのシンプルさにあります：数千の要素に対して異なるスタイルシートをロードしたり、クラスの切り替えを行ったりする代わりに、単一の要素の属性を変更するだけで、CSSがカスケードによって残りを処理します。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_テーマシステム用のcss構造&amp;quot;&amp;gt;テーマシステム用のCSS構造&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;「堅牢なテーマシステムを実装するための完全なCSS構造」&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-css hljs&amp;quot; data-lang=&amp;quot;css&amp;quot;&amp;gt;/**
 * SYSTÈME DE THÈME COMPLET
 * Utilise les Custom Properties CSS pour une maintenance facile
 */

/* ============================================
   THÈME PAR DÉFAUT (LIGHT)
   Défini sur :root pour être le fallback
   ============================================ */
:root {
  /* Couleurs de base */
  --color-primary: #0d6efd;
  --color-secondary: #6c757d;
  --color-success: #198754;
  --color-danger: #dc3545;
  --color-warning: #ffc107;
  --color-info: #0dcaf0;

  /* Couleurs de fond */
  --bg-primary: #ffffff;
  --bg-secondary: #f8f9fa;
  --bg-tertiary: #e9ecef;

  /* Couleurs de texte */
  --text-primary: #212529;
  --text-secondary: #6c757d;
  --text-tertiary: #adb5bd;

  /* Couleurs de bordure */
  --border-color: #dee2e6;
  --border-color-subtle: #e9ecef;

  /* Couleurs d&amp;#39;ombre */
  --shadow-sm: rgba(0, 0, 0, 0.075);
  --shadow-md: rgba(0, 0, 0, 0.15);
  --shadow-lg: rgba(0, 0, 0, 0.25&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;</description>
        </item><item>
            <title>Gradleプラグインの機能テストにおける効果的なログ</title>
            <link >https://cheroliv.com/blog/2025/0097_gradle_plugin_dev_func_test_logger_post.html</link>
            <pubDate>Fri, 7 Nov 2025 00:00:00 +0000</pubDate>
            <guid isPermaLink="false">blog/2025/0097_gradle_plugin_dev_func_test_logger_post.html</guid>
            <description>&amp;lt;div id=&amp;quot;toc&amp;quot; class=&amp;quot;toc&amp;quot;&amp;gt;
&amp;lt;div id=&amp;quot;toctitle&amp;quot;&amp;gt;Table of Contents&amp;lt;/div&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel1&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_はじめに&amp;quot;&amp;gt;はじめに&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_問題_gradlerunnerへの依存&amp;quot;&amp;gt;問題: GradleRunnerへの依存&amp;lt;/a&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel2&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_プラグイン開発のコンテキスト&amp;quot;&amp;gt;プラグイン開発のコンテキスト&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_ロギングのジレンマ&amp;quot;&amp;gt;ロギングのジレンマ&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_誤った良いアイデア&amp;quot;&amp;gt;�誤った良いアイデア&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_ソリューション_独立ロガー&amp;quot;&amp;gt;ソリューション: 独立ロガー&amp;lt;/a&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel2&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_推奨アーキテクチャ&amp;quot;&amp;gt;推奨アーキテクチャ&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_実行フロー&amp;quot;&amp;gt;実行フロー&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_完全実装&amp;quot;&amp;gt;完全実装&amp;lt;/a&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel2&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_gradleの依存関係&amp;quot;&amp;gt;Gradleの依存関係&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_設定_logback&amp;quot;&amp;gt;設定 Logback&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_完全なテストクラス&amp;quot;&amp;gt;完全なテストクラス&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_マルチレベルログスキーム&amp;quot;&amp;gt;マルチレベルログスキーム&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_ベストプラクティス&amp;quot;&amp;gt;ベストプラクティス&amp;lt;/a&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel2&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_推奨されるロギング構造&amp;quot;&amp;gt;推奨されるロギング構造&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_可読性のための視覚的なシンボル&amp;quot;&amp;gt;可読性のための視覚的なシンボル&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_出力からの情報抽出&amp;quot;&amp;gt;出力からの情報抽出&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_比較_前後&amp;quot;&amp;gt;比較 前後&amp;lt;/a&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel2&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_前問題のあるアプローチ&amp;quot;&amp;gt;前：問題のあるアプローチ&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_後_頑健なアプローチ&amp;quot;&amp;gt;後 : 頑健なアプローチ&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_サマリーダイアグラム&amp;quot;&amp;gt;サマリーダイアグラム&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_避けるべき罠&amp;quot;&amp;gt;�避けるべき罠&amp;lt;/a&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel2&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_罠1忘れる_forwardoutput&amp;quot;&amp;gt;�❌ 罠1：忘れる `.forwardOutput()&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_罠_2番_ロガー_未初期化&amp;quot;&amp;gt;�❌ 罠 2番 : ロガー 未初期化&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_罠_3_過剰なログ&amp;quot;&amp;gt;�❌ 罠 3 : 過剰なログ&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_結果とメトリクス&amp;quot;&amp;gt;結果とメトリクス&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_結論&amp;quot;&amp;gt;結論&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_資源&amp;quot;&amp;gt;資源&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_もっと先へ&amp;quot;&amp;gt;もっと先へ&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_はじめに&amp;quot;&amp;gt;はじめに&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;Gradleプラグインの開発中、機能テストはGradleの実際の環境でのプラグインの動作を検証するために不可欠です。しかし、重要な質問がすぐに浮上します：&amp;lt;strong&amp;gt;どのようにすれば &amp;lt;code&amp;gt;GradleRunner&amp;lt;/code&amp;gt; と問題のある依存関係を作らずに効果的なロギングシステムを構築できますか？&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;この記事では、次のことを探求します：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;Gradleの機能テストにおけるロギングの問題&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;SLF4J と Logback を使用した堅牢なソリューションのアーキテクチャ&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;具体的な例を含む完全な実装&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;良いプラクティスと避けるべき罠&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_問題_gradlerunnerへの依存&amp;quot;&amp;gt;問題: GradleRunnerへの依存&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_プラグイン開発のコンテキスト&amp;quot;&amp;gt;プラグイン開発のコンテキスト&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;Gradleプラグインを開発する際には、通常、`GradleRunner`&amp;lt;em&amp;gt;Gradle TestKit&amp;lt;/em&amp;gt; を使用してテストビルドを実行する :&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-kotlin hljs&amp;quot; data-lang=&amp;quot;kotlin&amp;quot;&amp;gt;@Test
fun `test my plugin`() {
    val result = GradleRunner.create()
        .withProjectDir(projectDir)
        .withArguments(&amp;quot;myTask&amp;quot;)
        .build()

    // Comment logger efficacement ici ?
}&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_ロギングのジレンマ&amp;quot;&amp;gt;ロギングのジレンマ&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;主な問題は次のとおりです：&amp;lt;strong&amp;gt;ロギングは、初期化が確実でないオブジェクトに依存してはならない。&amp;lt;/strong&amp;gt;。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
!define RECTANGLE class

skinparam backgroundColor #FEFEFE
skinparam componentStyle rectangle

package &amp;quot;問題的アーキテクチャ&amp;quot; {
    RECTANGLE Test {
        + runTest()
    }

    RECTANGLE GradleRunner {
        + build()
        + getLogger() ❌
    }

    RECTANGLE Logger {
        + info()
        + debug()
    }

    Test --&amp;amp;gt; GradleRunner : dépend de
    Logger ..&amp;amp;gt; GradleRunner : dépend de ❌
}

note right of Logger
  Problème: Le logger dépend
  du GradleRunner qui peut
  ne pas être initialisé
end note

@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_誤った良いアイデア&amp;quot;&amp;gt;�誤った良いアイデア&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;admonitionblock warning&amp;quot;&amp;gt;
&amp;lt;table&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;icon&amp;quot;&amp;gt;
&amp;lt;i class=&amp;quot;fa icon-warning&amp;quot; title=&amp;quot;Warning&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;
&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;これをしないでください :&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-kotlin hljs&amp;quot; data-lang=&amp;quot;kotlin&amp;quot;&amp;gt;// ❌ MAUVAIS: Tentative d&amp;#39;obtenir un logger du runner
val runner = GradleRunner.create()
val logger = runner.logger // N&amp;#39;existe pas !
// ❌ MAUVAIS: Logger partagé initialisé tardivement
lateinit var logger: Logger
@BeforeEach
fun setup() {
    logger = LoggerFactory.getLogger(...)
}&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/table&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_ソリューション_独立ロガー&amp;quot;&amp;gt;ソリューション: 独立ロガー&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_推奨アーキテクチャ&amp;quot;&amp;gt;推奨アーキテクチャ&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;解決策はロガーを使用することである&amp;lt;strong&amp;gt;完全に独立&amp;lt;/strong&amp;gt; du &amp;lt;code&amp;gt;GradleRunner&amp;lt;/code&amp;gt;, テストクラスレベルで初期化された&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
!define RECTANGLE class

skinparam backgroundColor #FEFEFE
skinparam componentStyle rectangle

package &amp;quot;正しいアーキテクチャ&amp;quot; {
    RECTANGLE TestClass {
        + {static} logger: Logger ✓
        + runTest()
    }

    RECTANGLE SLF4J {
        + LoggerFactory
    }

    RECTANGLE GradleRunner {
        + build()
        + forwardOutput()
    }

    RECTANGLE &amp;quot;コンソール出力&amp;quot; as Output {
        + captured text
    }

    TestClass --&amp;amp;gt; SLF4J : utilise ✓
    TestClass --&amp;amp;gt; GradleRunner : utilise
    GradleRunner --&amp;amp;gt; Output : génère
    TestClass --&amp;amp;gt; Output : analyse
}

note top of TestClass
  Le logger est initialisé
  indépendamment du GradleRunner
end note

note bottom of GradleRunner
  .forwardOutput() permet
  de capturer la sortie
  pour analyse
end note

@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_実行フロー&amp;quot;&amp;gt;実行フロー&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
!theme plain
skinparam backgroundColor #FEFEFE

participant &amp;quot;JUnit&amp;quot; as junit
participant &amp;quot;テストクラス&amp;quot; as test
participant &amp;quot;ロガー (SLF4J)&amp;quot; as logger
participant &amp;quot;GradleRunner&amp;quot; as runner
participant &amp;quot;Gradle ビルド&amp;quot; as gradle

activate junit
junit -&amp;amp;gt; test : load class
activate test

test -&amp;amp;gt; logger : initialize (companion)
activate logger
logger --&amp;amp;gt; test : logger ready ✓
deactivate logger

junit -&amp;amp;gt; test : @BeforeAll
test -&amp;amp;gt; logger : info(&amp;quot;Initialisation...&amp;quot;)

junit -&amp;amp;gt; test : @BeforeEach
test -&amp;amp;gt; logger : debug(&amp;quot;セットアップテスト...&amp;quot;)

junit -&amp;amp;gt; test : @Test
test -&amp;amp;gt; logger : info(&amp;quot;開始...&amp;quot;)

test -&amp;amp;gt; runner : create()
activate runner
test -&amp;amp;gt; runner : .forwardOutput()
test -&amp;amp;gt; runner : .withArguments(...)
test -&amp;amp;gt; runner : .build()

runner -&amp;amp;gt; gradle : execute build
activate gradle
gradle --&amp;amp;gt; runner : output text
deactivate gradle

runner --&amp;amp;gt; test : BuildResult + output
deactivate runner

test -&amp;amp;gt; logger : debug(&amp;quot;出力を分析中...&amp;quot;)
test -&amp;amp;gt; test : analyze output
test -&amp;amp;gt; logger : info(&amp;quot;�✓ テストに合格しました&amp;quot;)

test --&amp;amp;gt; junit : success
deactivate test
deactivate junit

@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_完全実装&amp;quot;&amp;gt;完全実装&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_gradleの依存関係&amp;quot;&amp;gt;Gradleの依存関係&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;必要な依存関係をあなたのに追加してください`build.gradle.kts`:&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-kotlin hljs&amp;quot; data-lang=&amp;quot;kotlin&amp;quot;&amp;gt;dependencies {
    // Pour les tests fonctionnels
    testImplementation(gradleTestKit())
    testImplementation(&amp;quot;org.junit.jupiter:junit-jupiter:5.10.2&amp;quot;)

    // Pour le logging
    testImplementation(&amp;quot;org.slf4j:slf4j-api:2.0.17&amp;quot;)
    testRuntimeOnly(&amp;quot;ch.qos.logback:logback-classic:1.4.14&amp;quot;)

    // Pour les assertions
    testImplementation(&amp;quot;org.assertj:assertj-core:3.27.6&amp;quot;)
}

tasks.test {
    useJUnitPlatform()
}&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_設定_logback&amp;quot;&amp;gt;設定 Logback&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;ファイルを作成してください`src/test/resources/logback-test.xml`:&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-xml hljs&amp;quot; data-lang=&amp;quot;xml&amp;quot;&amp;gt;&amp;amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot;?&amp;amp;gt;
&amp;amp;lt;configuration&amp;amp;gt;
    &amp;amp;lt;!-- Appender console avec format lisible --&amp;amp;gt;
    &amp;amp;lt;appender name=&amp;quot;STDOUT&amp;quot; class=&amp;quot;ch.qos.logback.core.ConsoleAppender&amp;quot;&amp;amp;gt;
        &amp;amp;lt;encoder&amp;amp;gt;
            &amp;amp;lt;pattern&amp;amp;gt;%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n&amp;amp;lt;/pattern&amp;amp;gt;
        &amp;amp;lt;/encoder&amp;amp;gt;
    &amp;amp;lt;/appender&amp;amp;gt;

    &amp;amp;lt;!-- Appender fichier pour conservation --&amp;amp;gt;
    &amp;amp;lt;appender name=&amp;quot;FILE&amp;quot; class=&amp;quot;ch.qos.logback.core.FileAppender&amp;quot;&amp;amp;gt;
        &amp;amp;lt;file&amp;amp;gt;build/test-results/functional-tests.log&amp;amp;lt;/file&amp;amp;gt;
        &amp;amp;lt;encoder&amp;amp;gt;
            &amp;amp;lt;pattern&amp;amp;gt;%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n&amp;amp;lt;/pattern&amp;amp;gt;
        &amp;amp;lt;/encoder&amp;amp;gt;
    &amp;amp;lt;/appender&amp;amp;gt;

    &amp;amp;lt;!-- Logger pour vos tests --&amp;amp;gt;
    &amp;amp;lt;logger name=&amp;quot;com.cheroliv.bakery&amp;quot; level=&amp;quot;DEBUG&amp;quot;/&amp;amp;gt;

    &amp;amp;lt;!-- Réduire le bruit de Gradle --&amp;amp;gt;
    &amp;amp;lt;logger name=&amp;quot;org.gradle&amp;quot; level=&amp;quot;WARN&amp;quot;/&amp;amp;gt;

    &amp;amp;lt;!-- Configuration racine --&amp;amp;gt;
    &amp;amp;lt;root level=&amp;quot;INFO&amp;quot;&amp;amp;gt;
        &amp;amp;lt;appender-ref ref=&amp;quot;STDOUT&amp;quot;/&amp;amp;gt;
        &amp;amp;lt;appender-ref ref=&amp;quot;FILE&amp;quot;/&amp;amp;gt;
    &amp;amp;lt;/root&amp;amp;gt;
&amp;amp;lt;/configuration&amp;amp;gt;&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_完全なテストクラス&amp;quot;&amp;gt;完全なテストクラス&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-kotlin hljs&amp;quot; data-lang=&amp;quot;kotlin&amp;quot;&amp;gt;package com.cheroliv.bakery

import org.gradle.testkit.runner.GradleRunner
import org.gradle.testkit.runner.TaskOutcome
import org.junit.jupiter.api.*
import org.junit.jupiter.api.TestInstance.Lifecycle.PER_CLASS
import org.junit.jupiter.api.io.TempDir
import org.slf4j.Logger
import org.slf4j.LoggerFactory
import java.io.File
import kotlin.test.assertEquals
import kotlin.test.assertTrue

@TestInstance(PER_CLASS)
class BakeryPluginFunctionalTest {

    @field:TempDir
    lateinit var projectDir: File

    private val buildFile by lazy { projectDir.resolve(&amp;quot;build.gradle.kts&amp;quot;) }
    private val settingsFile by lazy { projectDir.resolve(&amp;quot;settings.gradle.kts&amp;quot;) }

    companion object {
        // ✓ Logger indépendant, initialisé au chargement de la classe
        private val logger: Logger = LoggerFactory.getLogger(
            BakeryPluginFunctionalTest::class.java
        )

        @JvmStatic
        @BeforeAll
        fun globalSetup() {
            logger.info(&amp;quot;═&amp;quot;.repeat(60))
            logger.info(&amp;quot;DÉMARRAGE DE LA SUITE DE TESTS FONCTIONNELS&amp;quot;)
            logger.info(&amp;quot;═&amp;quot;.repeat(60))
        }

        @JvmStatic
        @AfterAll
        fun globalTeardown() {
            logger.info(&amp;quot;═&amp;quot;.repeat(60))
            logger.info(&amp;quot;FIN DE LA SUITE DE TESTS&amp;quot;)
            logger.info(&amp;quot;═&amp;quot;.repeat(60))
        }
    }

    @BeforeEach
    fun setup() {
        logger.info(&amp;quot;─&amp;quot;.repeat(60))
        logger.info(&amp;quot;Préparation de l&amp;#39;environnement de test&amp;quot;)
        logger.debug(&amp;quot;Répertoire de test: ${projectDir.absolutePath}&amp;quot;)

        settingsFile.writeText(&amp;quot;&amp;quot;&amp;quot;
            rootProject.name = &amp;quot;test-bakery-project&amp;quot;
        &amp;quot;&amp;quot;&amp;quot;.trimIndent())

        logger.debug(&amp;quot;✓ settings.gradle.kts créé&amp;quot;)
    }

    @AfterEach
    fun teardown(testInfo: TestInfo) {
        logger.info(&amp;quot;✓ Test terminé: ${testInfo.displayName}&amp;quot;)
        logger.info(&amp;quot;─&amp;quot;.repeat(60))
    }

    @Test
    fun `plugin can be applied successfully`() {
        logger.info(&amp;quot;TEST: Application du plugin Bakery&amp;quot;)

        buildFile.writeText(&amp;quot;&amp;quot;&amp;quot;
            plugins {
                id(&amp;quot;com.cheroliv.bakery&amp;quot;)
            }
        &amp;quot;&amp;quot;&amp;quot;.trimIndent())

        logger.debug(&amp;quot;Fichier build.gradle.kts créé&amp;quot;)
        logger.debug(&amp;quot;Lancement du build Gradle...&amp;quot;)

        val startTime = System.currentTimeMillis()

        val result = GradleRunner.create()
            .forwardOutput() // ← Important : capture la sortie
            .withPluginClasspath()
            .withArguments(&amp;quot;tasks&amp;quot;, &amp;quot;--group=bakery&amp;quot;, &amp;quot;--stacktrace&amp;quot;)
            .withProjectDir(projectDir)
            .build()

        val duration = System.currentTimeMillis() - startTime
        logger.info(&amp;quot;Build terminé en ${duration}ms&amp;quot;)

        // Analyse de la sortie
        logger.debug(&amp;quot;Analyse de la sortie Gradle...&amp;quot;)
        val outputLines = result.output.lines()
        logger.debug(&amp;quot;Nombre de lignes capturées: ${outputLines.size}&amp;quot;)

        // Validation
        val expectedTasks = listOf(&amp;quot;bake&amp;quot;, &amp;quot;printConfigPath&amp;quot;, &amp;quot;printJBakeClasspath&amp;quot;)
        logger.info(&amp;quot;Vérification des tâches attendues:&amp;quot;)

        expectedTasks.forEach { task -&amp;amp;gt;
            val found = result.output.contains(task)
            logger.debug(&amp;quot;  ${if (found) &amp;quot;✓&amp;quot; else &amp;quot;✗&amp;quot;} $task&amp;quot;)
            assertTrue(found, &amp;quot;Task &amp;#39;$task&amp;#39; should be available&amp;quot;)
        }

        logger.info(&amp;quot;✓ Plugin appliqué avec succès - ${expectedTasks.size} tâches trouvées&amp;quot;)
    }

    @Test
    fun `bake task executes and prints version`() {
        logger.info(&amp;quot;TEST: Exécution de la tâche &amp;#39;bake&amp;#39;&amp;quot;)

        buildFile.writeText(&amp;quot;&amp;quot;&amp;quot;
            plugins {
                id(&amp;quot;com.cheroliv.bakery&amp;quot;)
            }
        &amp;quot;&amp;quot;&amp;quot;.trimIndent())

        logger.debug(&amp;quot;Exécution de &amp;#39;gradle bake&amp;#39;...&amp;quot;)

        val result = GradleRunner.create()
            .forwardOutput()
            .withPluginClasspath()
            .withArguments(&amp;quot;bake&amp;quot;, &amp;quot;--info&amp;quot;) // --info pour plus de détails
            .withProjectDir(projectDir)
            .build()

        // Extraction d&amp;#39;informations depuis la sortie
        logger.debug(&amp;quot;Recherche du message &amp;#39;Baking site&amp;#39;...&amp;quot;)
        val hasBakingMessage = result.output.contains(&amp;quot;Baking site with Bakery Plugin!&amp;quot;)

        logger.debug(&amp;quot;Recherche de la version JBake...&amp;quot;)
        val hasVersionMessage = result.output.contains(&amp;quot;Using JBake version:&amp;quot;)

        // Extraction de la version (si présente)
        val versionRegex = Regex(&amp;quot;Using JBake version: (.+)&amp;quot;)
        val versionMatch = versionRegex.find(result.output)
        if (versionMatch != null) {
            val version = versionMatch.groupValues[1]
            logger.info(&amp;quot;Version JBake détectée: $version&amp;quot;)
        }

        // Validation
        assertTrue(hasBakingMessage, &amp;quot;Message &amp;#39;Baking site&amp;#39; attendu&amp;quot;)
        assertTrue(hasVersionMessage, &amp;quot;Message de version attendu&amp;quot;)
        assertEquals(TaskOutcome.SUCCESS, result.task(&amp;quot;:bake&amp;quot;)?.outcome)

        logger.info(&amp;quot;✓ Tâche &amp;#39;bake&amp;#39; exécutée avec succès&amp;quot;)
    }

    @Test
    fun `analyze output with structured logging`() {
        logger.info(&amp;quot;TEST: Analyse structurée de la sortie&amp;quot;)

        buildFile.writeText(&amp;quot;&amp;quot;&amp;quot;
            plugins {
                id(&amp;quot;com.cheroliv.bakery&amp;quot;)
            }

            task(&amp;quot;diagnostics&amp;quot;) {
                doLast {
                    println(&amp;quot;[DIAG] Project: ${&amp;#39;$&amp;#39;}{project.name}&amp;quot;)
                    println(&amp;quot;[DIAG] Build dir: ${&amp;#39;$&amp;#39;}{project.buildDir}&amp;quot;)
                    println(&amp;quot;[DIAG] Plugin applied: true&amp;quot;)

                    val config = configurations.findByName(&amp;quot;jbakeRuntime&amp;quot;)
                    println(&amp;quot;[DIAG] JBake config exists: ${&amp;#39;$&amp;#39;}{config != null}&amp;quot;)

                    if (config != null) {
                        println(&amp;quot;[DIAG] Dependencies count: ${&amp;#39;$&amp;#39;}{config.dependencies.size}&amp;quot;)
                    }
                }
            }
        &amp;quot;&amp;quot;&amp;quot;.trimIndent())

        logger.debug(&amp;quot;Exécution de la tâche diagnostics...&amp;quot;)

        val result = GradleRunner.create()
            .forwardOutput()
            .withPluginClasspath()
            .withArguments(&amp;quot;diagnostics&amp;quot;, &amp;quot;--quiet&amp;quot;)
            .withProjectDir(projectDir)
            .build()

        // Analyse structurée
        logger.info(&amp;quot;Extraction des informations de diagnostic:&amp;quot;)

        val diagLines = result.output.lines()
            .filter { it.startsWith(&amp;quot;[DIAG]&amp;quot;) }

        logger.debug(&amp;quot;Nombre de lignes de diagnostic: ${diagLines.size}&amp;quot;)

        diagLines.forEach { line -&amp;amp;gt;
            logger.info(&amp;quot;  $line&amp;quot;)

            // Analyse spécifique par type de ligne
            when {
                line.contains(&amp;quot;Project:&amp;quot;) -&amp;amp;gt; {
                    val projectName = line.substringAfter(&amp;quot;Project:&amp;quot;).trim()
                    logger.debug(&amp;quot;    → Nom du projet extrait: &amp;#39;$projectName&amp;#39;&amp;quot;)
                }
                line.contains(&amp;quot;Dependencies count:&amp;quot;) -&amp;amp;gt; {
                    val count = line.substringAfter(&amp;quot;count:&amp;quot;).trim()
                    logger.debug(&amp;quot;    → Nombre de dépendances: $count&amp;quot;)
                }
            }
        }

        assertTrue(diagLines.isNotEmpty(), &amp;quot;Des lignes de diagnostic devraient être présentes&amp;quot;)
        logger.info(&amp;quot;✓ Analyse structurée terminée - ${diagLines.size} lignes analysées&amp;quot;)
    }

    @Test
    fun `test with error handling`() {
        logger.info(&amp;quot;TEST: Gestion d&amp;#39;erreurs avec logging&amp;quot;)

        buildFile.writeText(&amp;quot;&amp;quot;&amp;quot;
            plugins {
                id(&amp;quot;com.cheroliv.bakery&amp;quot;)
            }
        &amp;quot;&amp;quot;&amp;quot;.trimIndent())

        try {
            logger.debug(&amp;quot;Tentative d&amp;#39;exécution...&amp;quot;)

            val result = GradleRunner.create()
                .forwardOutput()
                .withPluginClasspath()
                .withArguments(&amp;quot;printJBakeClasspath&amp;quot;)
                .withProjectDir(projectDir)
                .build()

            val outcome = result.task(&amp;quot;:printJBakeClasspath&amp;quot;)?.outcome
            logger.info(&amp;quot;Outcome: $outcome&amp;quot;)

            if (outcome == TaskOutcome.SUCCESS) {
                logger.info(&amp;quot;✓ Exécution réussie&amp;quot;)
            } else {
                logger.warn(&amp;quot;⚠ Outcome inattendu: $outcome&amp;quot;)
            }

            assertEquals(TaskOutcome.SUCCESS, outcome)

        } catch (e: Exception) {
            logger.error(&amp;quot;✗ Échec du test&amp;quot;, e)
            logger.error(&amp;quot;Type d&amp;#39;exception: ${e.javaClass.simpleName}&amp;quot;)
            logger.error(&amp;quot;Message: ${e.message}&amp;quot;)

            // Log de la stack trace si nécessaire
            if (logger.isDebugEnabled) {
                logger.debug(&amp;quot;Stack trace complète:&amp;quot;, e)
            }

            throw e
        }
    }
}&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_マルチレベルログスキーム&amp;quot;&amp;gt;マルチレベルログスキーム&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
!theme plain
skinparam backgroundColor #FEFEFE

package &amp;quot;ロギングレベル&amp;quot; {

    rectangle &amp;quot;痕跡&amp;quot; #E8E8E8 {
        note
            Détails d&amp;#39;exécution très fins
            • Valeurs de variables
            • Appels de méthodes internes
        end note
    }

    rectangle &amp;quot;DEBUG&amp;quot; #D0E8FF {
        note
            Informations de débogage
            • Étapes intermédiaires
            • Contenu des fichiers créés
            • Analyse de la sortie Gradle
        end note
    }

    rectangle &amp;quot;情報&amp;quot; #C8FFC8 {
        note
            Informations principales
            • Début/fin de test
            • Résultats de validation
            • Durée d&amp;#39;exécution
        end note
    }

    rectangle &amp;quot;警告&amp;quot; #FFFFC8 {
        note
            Avertissements
            • Comportements inattendus
            • Outcomes inhabituels
        end note
    }

    rectangle &amp;quot;エラー&amp;quot; #FFC8C8 {
        note
            Erreurs
            • Échecs de test
            • Exceptions
            • Stack traces
        end note
    }
}

@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_ベストプラクティス&amp;quot;&amp;gt;ベストプラクティス&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_推奨されるロギング構造&amp;quot;&amp;gt;推奨されるロギング構造&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-kotlin hljs&amp;quot; data-lang=&amp;quot;kotlin&amp;quot;&amp;gt;@Test
fun `mon test`() {
    // 1. LOG: Début du test
    logger.info(&amp;quot;TEST: Description du test&amp;quot;)

    // 2. LOG: Préparation
    logger.debug(&amp;quot;Préparation des fichiers...&amp;quot;)
    buildFile.writeText(&amp;quot;...&amp;quot;)
    logger.debug(&amp;quot;✓ Fichiers préparés&amp;quot;)

    // 3. LOG: Exécution
    logger.debug(&amp;quot;Lancement du build...&amp;quot;)
    val startTime = System.currentTimeMillis()

    val result = GradleRunner.create()
        .forwardOutput()
        .withArguments(&amp;quot;task&amp;quot;)
        .build()

    val duration = System.currentTimeMillis() - startTime
    logger.info(&amp;quot;Build terminé en ${duration}ms&amp;quot;)

    // 4. LOG: Analyse
    logger.debug(&amp;quot;Analyse des résultats...&amp;quot;)
    // ... validations ...

    // 5. LOG: Conclusion
    logger.info(&amp;quot;✓ Test réussi&amp;quot;)
}&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_可読性のための視覚的なシンボル&amp;quot;&amp;gt;可読性のための視覚的なシンボル&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;Unicode記号を使用してログの可読性を向上させなさい：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-kotlin hljs&amp;quot; data-lang=&amp;quot;kotlin&amp;quot;&amp;gt;logger.info(&amp;quot;✓ Succès&amp;quot;)
logger.info(&amp;quot;✗ Échec&amp;quot;)
logger.info(&amp;quot;⚠ Attention&amp;quot;)
logger.info(&amp;quot;→ Étape suivante&amp;quot;)
logger.info(&amp;quot;═&amp;quot;.repeat(60)) // Séparateur principal
logger.info(&amp;quot;─&amp;quot;.repeat(60)) // Séparateur secondaire&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_出力からの情報抽出&amp;quot;&amp;gt;出力からの情報抽出&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-kotlin hljs&amp;quot; data-lang=&amp;quot;kotlin&amp;quot;&amp;gt;// Recherche simple
val hasMessage = result.output.contains(&amp;quot;Expected message&amp;quot;)

// Extraction avec regex
val versionRegex = Regex(&amp;quot;Version: (.+)&amp;quot;)
val version = versionRegex.find(result.output)?.groupValues?.get(1)

// Filtrage de lignes
val errorLines = result.output.lines()
    .filter { it.contains(&amp;quot;ERROR&amp;quot;) }

errorLines.forEach { logger.error(&amp;quot;Gradle error: $it&amp;quot;) }&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_比較_前後&amp;quot;&amp;gt;比較 前後&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_前問題のあるアプローチ&amp;quot;&amp;gt;前：問題のあるアプローチ&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-kotlin hljs&amp;quot; data-lang=&amp;quot;kotlin&amp;quot;&amp;gt;class MyTest {
    lateinit var logger: Logger // ❌ Initialisé tardivement

    @BeforeEach
    fun setup() {
        logger = LoggerFactory.getLogger(...) // ❌ Dépendance
    }

    @Test
    fun test() {
        val runner = GradleRunner.create()
        logger.info(&amp;quot;Testing...&amp;quot;) // ⚠ Peut échouer
    }
}&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_後_頑健なアプローチ&amp;quot;&amp;gt;後 : 頑健なアプローチ&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-kotlin hljs&amp;quot; data-lang=&amp;quot;kotlin&amp;quot;&amp;gt;class MyTest {
    companion object {
        private val logger = LoggerFactory.getLogger(...) // ✓ Indépendant
    }

    @Test
    fun test() {
        logger.info(&amp;quot;TEST: Starting...&amp;quot;) // ✓ Toujours disponible

        val result = GradleRunner.create()
            .forwardOutput() // ✓ Capture la sortie
            .build()

        logger.debug(&amp;quot;Output: ${result.output}&amp;quot;) // ✓ Analyse
    }
}&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_サマリーダイアグラム&amp;quot;&amp;gt;サマリーダイアグラム&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
!theme plain
skinparam backgroundColor #FEFEFE

title 機能テストにおける完全なロギングフロー
actor &amp;quot;開発者&amp;quot; as dev
participant &amp;quot;JUnit&amp;quot; as junit
participant &amp;quot;テストクラス&amp;quot; as test
participant &amp;quot;Logger
(SLF4J)&amp;quot; as logger
participant &amp;quot;Logback&amp;quot; as logback
participant &amp;quot;グラドルランナー&amp;quot; as runner
participant &amp;quot;コンソール/ファイル&amp;quot; as output

dev -&amp;amp;gt; junit : lance les tests

activate junit
junit -&amp;amp;gt; test : charge la classe
activate test

test -&amp;amp;gt; logger : initialize (companion)
activate logger
logger -&amp;amp;gt; logback : configure
activate logback
logback --&amp;amp;gt; logger : ready
deactivate logback
logger --&amp;amp;gt; test : ✓
deactivate logger

== Phase de Setup ==

junit -&amp;amp;gt; test : @BeforeAll
test -&amp;amp;gt; logger : info(&amp;quot;初期化&amp;quot;)
logger -&amp;amp;gt; output : [INFO] Initialisation

junit -&amp;amp;gt; test : @BeforeEach
test -&amp;amp;gt; logger : debug(&amp;quot;セットアップ テスト&amp;quot;)
logger -&amp;amp;gt; output : [DEBUG] Setup test

== Phase de Test ==

junit -&amp;amp;gt; test : @Test
test -&amp;amp;gt; logger : info(&amp;quot;始める&amp;quot;)
logger -&amp;amp;gt; output : [INFO] TEST: Starting

test -&amp;amp;gt; runner : create()
activate runner

test -&amp;amp;gt; runner : .forwardOutput()
test -&amp;amp;gt; runner : .build()

runner -&amp;amp;gt; runner : execute Gradle
runner --&amp;amp;gt; test : BuildResult + output text
deactivate runner

test -&amp;amp;gt; logger : debug(&amp;quot;出力を分析中&amp;quot;)
logger -&amp;amp;gt; output : [DEBUG] Analyzing output

test -&amp;amp;gt; test : assertions
test -&amp;amp;gt; logger : info(&amp;quot;�✓ テストに合格しました&amp;quot;)
logger -&amp;amp;gt; output : [INFO] ✓ Test passed

== Phase de Cleanup ==

junit -&amp;amp;gt; test : @AfterEach
test -&amp;amp;gt; logger : debug(&amp;quot;クリーンアップ&amp;quot;)
logger -&amp;amp;gt; output : [DEBUG] Cleanup

junit -&amp;amp;gt; test : @AfterAll
test -&amp;amp;gt; logger : info(&amp;quot;テストの終了&amp;quot;)
logger -&amp;amp;gt; output : [INFO] Fin des tests

test --&amp;amp;gt; junit : ✓ all tests passed
deactivate test
deactivate junit

dev &amp;amp;lt;-- junit : rapport de tests

@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_避けるべき罠&amp;quot;&amp;gt;�避けるべき罠&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_罠1忘れる_forwardoutput&amp;quot;&amp;gt;�❌ 罠1：忘れる `.forwardOutput()&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-kotlin hljs&amp;quot; data-lang=&amp;quot;kotlin&amp;quot;&amp;gt;// MAUVAIS: La sortie Gradle n&amp;#39;est pas capturée
val result = GradleRunner.create()
    .withArguments(&amp;quot;task&amp;quot;)
    .build()

// result.output sera vide !&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-kotlin hljs&amp;quot; data-lang=&amp;quot;kotlin&amp;quot;&amp;gt;// BON: La sortie est capturée
val result = GradleRunner.create()
    .forwardOutput() // ✓
    .withArguments(&amp;quot;task&amp;quot;)
    .build()&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_罠_2番_ロガー_未初期化&amp;quot;&amp;gt;�❌ 罠 2番 : ロガー 未初期化&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-kotlin hljs&amp;quot; data-lang=&amp;quot;kotlin&amp;quot;&amp;gt;// MAUVAIS
class Test {
    lateinit var logger: Logger // Peut ne pas être initialisé
}&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-kotlin hljs&amp;quot; data-lang=&amp;quot;kotlin&amp;quot;&amp;gt;// BON
class Test {
    companion object {
        private val logger = LoggerFactory.getLogger(...) // Toujours initialisé
    }
}&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_罠_3_過剰なログ&amp;quot;&amp;gt;�❌ 罠 3 : 過剰なログ&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-kotlin hljs&amp;quot; data-lang=&amp;quot;kotlin&amp;quot;&amp;gt;// MAUVAIS: Trop de logs DEBUG en production
logger.debug(&amp;quot;Variable a = $a&amp;quot;)
logger.debug(&amp;quot;Variable b = $b&amp;quot;)
logger.debug(&amp;quot;Variable c = $c&amp;quot;)
// ... 100 lignes de logs&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-kotlin hljs&amp;quot; data-lang=&amp;quot;kotlin&amp;quot;&amp;gt;// BON: Logging ciblé
logger.info(&amp;quot;Traitement de ${items.size} éléments&amp;quot;)
logger.debug(&amp;quot;Détails: ${items.take(5)}...&amp;quot;) // Échantillon seulement&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_結果とメトリクス&amp;quot;&amp;gt;結果とメトリクス&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;このアプローチでは、次のように得られます：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;table class=&amp;quot;tableblock frame-all grid-all stretch&amp;quot;&amp;gt;
&amp;lt;colgroup&amp;gt;
&amp;lt;col style=&amp;quot;width: 28.5714%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 42.8571%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 28.5715%;&amp;quot;&amp;gt;
&amp;lt;/colgroup&amp;gt;
&amp;lt;thead&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;th class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;メトリック&amp;lt;/th&amp;gt;
&amp;lt;th class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;前に&amp;lt;/th&amp;gt;
&amp;lt;th class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;後&amp;lt;/th&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/thead&amp;gt;
&amp;lt;tbody&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;コードの行&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;~50 lignes&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;約80行（＋60％）&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;デバッグ時間&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;~30分&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;~5分 (-83%)&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;�検出されたエラー&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;基本的&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;詳細&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;メンテナンス&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;難しい&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;シンプル&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;独立&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;❌ 結合された&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;独立した&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/tbody&amp;gt;
&amp;lt;/table&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_結論&amp;quot;&amp;gt;結論&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;Gradle プラグインの機能テストにおける堅牢なログ システムの導入は、シンプルな原則に基づいています :&amp;lt;strong&amp;gt;独立&amp;lt;/strong&amp;gt;。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;重要なポイント：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;olist arabic&amp;quot;&amp;gt;
&amp;lt;ol class=&amp;quot;arabic&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;独立ロガー&amp;lt;/strong&amp;gt;で初期化された`companion object`&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;SLF4JとLogback&amp;lt;/strong&amp;gt;: テスト済みで設定可能なスタック&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;.forwardOutput()&amp;lt;/strong&amp;gt;: Gradle出力のキャプチャ&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;構造化ログ&amp;lt;/strong&amp;gt;: INFO ステップのために, DEBUG 詳細のために&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;出力の分析&amp;lt;/strong&amp;gt;情報の抽出から`result.output`&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ol&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;このアプローチはテストを保証する&amp;lt;strong&amp;gt;メンテナンス可能&amp;lt;/strong&amp;gt;, &amp;lt;strong&amp;gt;デバッグ可能なもの&amp;lt;/strong&amp;gt; et &amp;lt;strong&amp;gt;頑丈&amp;lt;/strong&amp;gt;, しっかりとした設計の原則を尊重しながら。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_資源&amp;quot;&amp;gt;資源&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;https://docs.gradle.org/current/userguide/test_kit.html&amp;quot;&amp;gt;Gradle TestKit ドキュメント&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;https://www.slf4j.org/manual.html&amp;quot;&amp;gt;SLF4J マニュアル&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;https://logback.qos.ch/manual/configuration.html&amp;quot;&amp;gt;Logback 設定&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;https://github.com/gradle/gradle/tree/master/subprojects/test-kit&amp;quot;&amp;gt;Gradle TestKit ソースコード&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_もっと先へ&amp;quot;&amp;gt;もっと先へ&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;次回の記事では、探求します:&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;構造化ロギング付きの継続的インテグレーション&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;ログが組み込まれたHTMLテストレポート&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;JVMアタッチを使用した高度なデバッグ&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;パフォーマンスとロギングの最適化&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;em&amp;gt;この記事は、私の技術ブログにおける「Gradleプラグイン開発」シリーズの一部です。&amp;lt;/em&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;</description>
        </item><item>
            <title>AsciiDocで色付きの正方形を表示する : 実践ガイド</title>
            <link >https://cheroliv.com/blog/2025/0096_afficher-couleurs-asciidoc_post.html</link>
            <pubDate>Sat, 1 Nov 2025 00:00:00 +0000</pubDate>
            <guid isPermaLink="false">blog/2025/0096_afficher-couleurs-asciidoc_post.html</guid>
            <description>&amp;lt;div id=&amp;quot;toc&amp;quot; class=&amp;quot;toc&amp;quot;&amp;gt;
&amp;lt;div id=&amp;quot;toctitle&amp;quot;&amp;gt;Table of Contents&amp;lt;/div&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel1&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_導入&amp;quot;&amp;gt;導入&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_問題&amp;quot;&amp;gt;問題&amp;lt;/a&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel2&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_使用コンテキスト&amp;quot;&amp;gt;使用コンテキスト&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_考えられるアプローチ&amp;quot;&amp;gt;考えられるアプローチ&amp;lt;/a&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel3&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_オプション_1_unicode文字&amp;quot;&amp;gt;オプション 1 : Unicode文字&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_オプション_2_外部画像&amp;quot;&amp;gt;オプション 2 : 外部画像&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_オプション3_カスタムcssロール&amp;quot;&amp;gt;オプション3 : カスタムCSSロール&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_オプション4_htmlインジェクション_採用された解決策&amp;quot;&amp;gt;オプション4 : HTMLインジェクション (採用された解決策)&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_解決策_htmlインジェクション&amp;quot;&amp;gt;解決策 : HTMLインジェクション &amp;lt;/a&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel2&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_動作原理&amp;quot;&amp;gt;動作原理&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_実装&amp;quot;&amp;gt;実装&amp;lt;/a&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel3&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_cssプロパティの説明&amp;quot;&amp;gt;CSSプロパティの説明&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_完全な例&amp;quot;&amp;gt;完全な例&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_最適化とベストプラクティス&amp;quot;&amp;gt;最適化とベストプラクティス&amp;lt;/a&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel2&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_明るい色を管理する&amp;quot;&amp;gt;明るい色を管理する&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_正方形のサイズを調整する&amp;quot;&amp;gt;正方形のサイズを調整する&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_バリエーションを作成する&amp;quot;&amp;gt;バリエーションを作成する&amp;lt;/a&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel3&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_色付きの円&amp;quot;&amp;gt;色付きの円&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_色付きの枠線がある正方形&amp;quot;&amp;gt;色付きの枠線がある正方形&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_ソリューションアーキテクチャ&amp;quot;&amp;gt;ソリューションアーキテクチャ&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_利点と制限&amp;quot;&amp;gt;利点と制限&amp;lt;/a&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel2&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_利点&amp;quot;&amp;gt;利点&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_制限&amp;quot;&amp;gt;制限&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_アクセシビリティの向上&amp;quot;&amp;gt;アクセシビリティの向上&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_具体例テーマのドキュメンテーション&amp;quot;&amp;gt;具体例：テーマのドキュメンテーション&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_結論&amp;quot;&amp;gt;結論&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_リソース&amp;quot;&amp;gt;リソース&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_導入&amp;quot;&amp;gt;導入&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;技術ドキュメントを作成する際、特にスタイルガイドやユーザーインターフェース仕様では、カラーパレットを表示することがよくあります。AsciiDoc はドキュメント作成に非常に強力ですが、カラーサンプルを表示するためのネイティブな構文は提供されていません。この記事ではこの問題を検討し、HTML インジェクションに基づくエレガントな解決策を提案します。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_問題&amp;quot;&amp;gt;問題&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_使用コンテキスト&amp;quot;&amp;gt;使用コンテキスト&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;ウェブアプリケーションテーマのCSS変数をドキュメントしていると想像してください。次のものが必要です：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;olist arabic&amp;quot;&amp;gt;
&amp;lt;ol class=&amp;quot;arabic&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;16進数のカラーコードをリスト&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;各色の視覚的なプレビューを表示&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;ソースドキュメントの可読性を維持する&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;静的サイトジェネレーター（JBakeなど）との互換性を確保する&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ol&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
left to right direction
skinparam packageStyle rectangle

actor &amp;quot;技術ライター&amp;quot; as writer
actor &amp;quot;読者&amp;quot; as reader

rectangle &amp;quot;AsciiDoc ドキュメンテーション&amp;quot; {
  usecase &amp;quot;カラーパレットをドキュメントする&amp;quot; as UC1
  usecase &amp;quot;16進数コードを表示&amp;quot; as UC2
  usecase &amp;quot;色を表示&amp;quot; as UC3
  usecase &amp;quot;静的サイトを生成&amp;quot; as UC4
  usecase &amp;quot;ドキュメントを参照&amp;quot; as UC5
}

writer --&amp;amp;gt; UC1
UC1 ..&amp;amp;gt; UC2 : include
UC1 ..&amp;amp;gt; UC3 : include
UC1 --&amp;amp;gt; UC4
UC4 --&amp;amp;gt; UC5
UC5 &amp;amp;lt;-- reader
@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_考えられるアプローチ&amp;quot;&amp;gt;考えられるアプローチ&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;いくつかの解決策を検討することができます。AsciiDocドキュメントで色を表示するために：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
skinparam componentStyle rectangle

package &amp;quot;可能な解決策&amp;quot; {
  component &amp;quot;Unicode文字&amp;quot; as unicode
  component &amp;quot;外部の画像&amp;quot; as images
  component &amp;quot;カスタムCSSロール&amp;quot; as css
  component &amp;quot;HTMLインジェクション&amp;quot; as html
}

package &amp;quot;評価基準&amp;quot; {
  component &amp;quot;シンプルさ&amp;quot; as simple
  component &amp;quot;�携帯性&amp;quot; as portable
  component &amp;quot;パーソナライズ&amp;quot; as custom
  component &amp;quot;メンテナンス&amp;quot; as maintain
}

unicode -down-&amp;amp;gt; simple : ✓
unicode -down-&amp;amp;gt; portable : ✓
unicode -down-&amp;amp;gt; custom : ✗

images -down-&amp;amp;gt; simple : ✗
images -down-&amp;amp;gt; portable : ✗
images -down-&amp;amp;gt; custom : ✓

css -down-&amp;amp;gt; simple : ~
css -down-&amp;amp;gt; portable : ✗
css -down-&amp;amp;gt; custom : ✓

html -down-&amp;amp;gt; simple : ✓
html -down-&amp;amp;gt; portable : ✓
html -down-&amp;amp;gt; custom : ✓✓
html -down-&amp;amp;gt; maintain : ✓

note right of html
  Solution recommandée
end note
@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect3&amp;quot;&amp;gt;
&amp;lt;h4 id=&amp;quot;_オプション_1_unicode文字&amp;quot;&amp;gt;オプション 1 : Unicode文字&amp;lt;/h4&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;Unicode文字を使用して`&amp;amp;#9632;`(■) 簡単だが限定的である :&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-asciidoc hljs&amp;quot; data-lang=&amp;quot;asciidoc&amp;quot;&amp;gt;* ■ --accent-color: #7952b3 (violet Bootstrap)&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;制限&amp;lt;/strong&amp;gt; : 色の制御はありません、システムフォントに依存します。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect3&amp;quot;&amp;gt;
&amp;lt;h4 id=&amp;quot;_オプション_2_外部画像&amp;quot;&amp;gt;オプション 2 : 外部画像&amp;lt;/h4&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;各色ごとに PNG または SVG の画像を作成する：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-asciidoc hljs&amp;quot; data-lang=&amp;quot;asciidoc&amp;quot;&amp;gt;* image:colors/violet.svg[width=16] --accent-color: #7952b3&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;制限&amp;lt;/strong&amp;gt; :重いメンテナンス、ファイルの増殖、自動同期なし。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect3&amp;quot;&amp;gt;
&amp;lt;h4 id=&amp;quot;_オプション3_カスタムcssロール&amp;quot;&amp;gt;オプション3 : カスタムCSSロール&amp;lt;/h4&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;CSSクラスを定義し、AsciiDocのロールを使用して適用する：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-asciidoc hljs&amp;quot; data-lang=&amp;quot;asciidoc&amp;quot;&amp;gt;* [.color-violet]##■## --accent-color: #7952b3&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;制限&amp;lt;/strong&amp;gt; : 外部スタイルシートが必要、すべての可能な色の事前定義が必要&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect3&amp;quot;&amp;gt;
&amp;lt;h4 id=&amp;quot;_オプション4_htmlインジェクション_採用された解決策&amp;quot;&amp;gt;オプション4 : HTMLインジェクション (採用された解決策)&amp;lt;/h4&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;マクロを使用する``HTMLをインラインスタイルで注入するために :&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-asciidoc hljs&amp;quot; data-lang=&amp;quot;asciidoc&amp;quot;&amp;gt;* pass:[&amp;amp;lt;span style=&amp;quot;display:inline-block;width:1em;height:1em;
background:#7952b3;vertical-align:middle;margin-right:0.5em&amp;quot;&amp;amp;gt;&amp;amp;lt;/span&amp;amp;gt;]
--accent-color: #7952b3 (violet Bootstrap)&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_解決策_htmlインジェクション&amp;quot;&amp;gt;解決策 : HTMLインジェクション &amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_動作原理&amp;quot;&amp;gt;動作原理&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;マクロ``AsciiDoc では、AsciiDoc プロセッサーによって解釈されない生のコンテンツを挿入できます。これにより、インライン CSS スタイルを持つ HTML を直接挿入できます。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
participant &amp;quot;ドキュメント\nAsciiDoc&amp;quot; as doc
participant &amp;quot;プロセッサー
AsciiDoc&amp;quot; as processor
participant &amp;quot;パス:[] マクロ&amp;quot; as pass
participant &amp;quot;HTML
最終&amp;quot; as html

doc -&amp;amp;gt; processor : Analyse document
processor -&amp;amp;gt; pass : Détecte pass:[]
pass -&amp;amp;gt; processor : Retourne HTML brut
processor -&amp;amp;gt; html : Insère sans transformation
html -&amp;amp;gt; html : Navigateur applique styles
@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_実装&amp;quot;&amp;gt;実装&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;ここに注入するHTML構造は：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-html hljs&amp;quot; data-lang=&amp;quot;html&amp;quot;&amp;gt;&amp;amp;lt;span style=&amp;quot;display:inline-block;
             width:1em;
             height:1em;
             background:#7952b3;
             vertical-align:middle;
             margin-right:0.5em&amp;quot;&amp;amp;gt;
&amp;amp;lt;/span&amp;amp;gt;&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect3&amp;quot;&amp;gt;
&amp;lt;h4 id=&amp;quot;_cssプロパティの説明&amp;quot;&amp;gt;CSSプロパティの説明&amp;lt;/h4&amp;gt;
&amp;lt;table class=&amp;quot;tableblock frame-all grid-all stretch&amp;quot;&amp;gt;
&amp;lt;colgroup&amp;gt;
&amp;lt;col style=&amp;quot;width: 25%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 75%;&amp;quot;&amp;gt;
&amp;lt;/colgroup&amp;gt;
&amp;lt;thead&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;th class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;所有&amp;lt;/th&amp;gt;
&amp;lt;th class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;機能&amp;lt;/th&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/thead&amp;gt;
&amp;lt;tbody&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;code&amp;gt;display:inline-block&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;インラインフローに留まりながら width/height を設定できるようにする&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;code&amp;gt;width:1em; height:1em&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;フォントサイズに対する正方形のサイズ (レスポンシブ)&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;code&amp;gt;background:#7952b3&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;表示する色（ニーズに応じて変数）&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;code&amp;gt;vertical-align:middle&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;正方形を隣接するテキストに合わせて揃える&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;code&amp;gt;margin-right:0.5em&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;正方形とテキストの間隔&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/tbody&amp;gt;
&amp;lt;/table&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_完全な例&amp;quot;&amp;gt;完全な例&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;テーマパレットの文書化例を以下に示します：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-asciidoc hljs&amp;quot; data-lang=&amp;quot;asciidoc&amp;quot;&amp;gt;== Thème Clair

* pass:[&amp;amp;lt;span style=&amp;quot;display:inline-block;width:1em;height:1em;background:#f8f9fa;border:1px solid #ccc;vertical-align:middle;margin-right:0.5em&amp;quot;&amp;amp;gt;&amp;amp;lt;/span&amp;amp;gt;] --bg-primary: `#f8f9fa` (blanc cassé)
* pass:[&amp;amp;lt;span style=&amp;quot;display:inline-block;width:1em;height:1em;background:#212529;vertical-align:middle;margin-right:0.5em&amp;quot;&amp;amp;gt;&amp;amp;lt;/span&amp;amp;gt;] --text-primary: `#212529` (noir très foncé)
* pass:[&amp;amp;lt;span style=&amp;quot;display:inline-block;width:1em;height:1em;background:#7952b3;vertical-align:middle;margin-right:0.5em&amp;quot;&amp;amp;gt;&amp;amp;lt;/span&amp;amp;gt;] --accent-color: `#7952b3` (violet Bootstrap)
* pass:[&amp;amp;lt;span style=&amp;quot;display:inline-block;width:1em;height:1em;background:#61428f;vertical-align:middle;margin-right:0.5em&amp;quot;&amp;amp;gt;&amp;amp;lt;/span&amp;amp;gt;] --accent-hover: `#61428f` (violet plus foncé)
* pass:[&amp;amp;lt;span style=&amp;quot;display:inline-block;width:1em;height:1em;background:#ffffff;border:1px solid #ccc;vertical-align:middle;margin-right:0.5em&amp;quot;&amp;amp;gt;&amp;amp;lt;/span&amp;amp;gt;] --card-bg: `#ffffff` (blanc)&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;次のレンダリングを生成する：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;ライトテーマ&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;span style=&amp;quot;display:inline-block;width:1em;height:1em;background:#f8f9fa;border:1px solid #ccc;vertical-align:middle;margin-right:0.5em&amp;quot;&amp;gt;&amp;lt;/span&amp;gt; --bg-primary:`#f8f9fa`(オフホワイト)&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;span style=&amp;quot;display:inline-block;width:1em;height:1em;background:#212529;vertical-align:middle;margin-right:0.5em&amp;quot;&amp;gt;&amp;lt;/span&amp;gt; --text-primary:`#212529`(非常に暗い黒)&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;span style=&amp;quot;display:inline-block;width:1em;height:1em;background:#7952b3;vertical-align:middle;margin-right:0.5em&amp;quot;&amp;gt;&amp;lt;/span&amp;gt; --accent-color:`#7952b3`(バイオレット Bootstrap)&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;span style=&amp;quot;display:inline-block;width:1em;height:1em;background:#61428f;vertical-align:middle;margin-right:0.5em&amp;quot;&amp;gt;&amp;lt;/span&amp;gt; --accent-hover:`#61428f`(より暗い紫)&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;span style=&amp;quot;display:inline-block;width:1em;height:1em;background:#ffffff;border:1px solid #ccc;vertical-align:middle;margin-right:0.5em&amp;quot;&amp;gt;&amp;lt;/span&amp;gt; --card-bg:`#ffffff`(白)&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_最適化とベストプラクティス&amp;quot;&amp;gt;最適化とベストプラクティス&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_明るい色を管理する&amp;quot;&amp;gt;明るい色を管理する&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;非常に薄い色（白、非常に薄いグレー）の場合は、白い背景でも見えるように枠線を追加してください：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-html hljs&amp;quot; data-lang=&amp;quot;html&amp;quot;&amp;gt;&amp;amp;lt;span style=&amp;quot;display:inline-block;width:1em;height:1em;
background:#ffffff;border:1px solid #ccc;
vertical-align:middle;margin-right:0.5em&amp;quot;&amp;amp;gt;&amp;amp;lt;/span&amp;amp;gt;&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;�灰色の境界線`border:1px solid #ccc`) は白い背景上の白い正方形を区切ることができます。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_正方形のサイズを調整する&amp;quot;&amp;gt;正方形のサイズを調整する&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;必要に応じて正方形のサイズを調整できます：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-asciidoc hljs&amp;quot; data-lang=&amp;quot;asciidoc&amp;quot;&amp;gt;* pass:[&amp;amp;lt;span style=&amp;quot;display:inline-block;width:1.5em;height:1.5em;background:#7952b3;vertical-align:middle;margin-right:0.5em&amp;quot;&amp;amp;gt;&amp;amp;lt;/span&amp;amp;gt;] Grand carré
* pass:[&amp;amp;lt;span style=&amp;quot;display:inline-block;width:0.8em;height:0.8em;background:#7952b3;vertical-align:middle;margin-right:0.5em&amp;quot;&amp;amp;gt;&amp;amp;lt;/span&amp;amp;gt;] Petit carré&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;単位の使用`em`フォントサイズに合わせて正方形が適応することを保証します。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_バリエーションを作成する&amp;quot;&amp;gt;バリエーションを作成する&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;特定のニーズに対して、さまざまな形を作ることができます：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect3&amp;quot;&amp;gt;
&amp;lt;h4 id=&amp;quot;_色付きの円&amp;quot;&amp;gt;色付きの円&amp;lt;/h4&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-asciidoc hljs&amp;quot; data-lang=&amp;quot;asciidoc&amp;quot;&amp;gt;* pass:[&amp;amp;lt;span style=&amp;quot;display:inline-block;width:1em;height:1em;background:#7952b3;border-radius:50%;vertical-align:middle;margin-right:0.5em&amp;quot;&amp;amp;gt;&amp;amp;lt;/span&amp;amp;gt;] Cercle violet&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect3&amp;quot;&amp;gt;
&amp;lt;h4 id=&amp;quot;_色付きの枠線がある正方形&amp;quot;&amp;gt;色付きの枠線がある正方形&amp;lt;/h4&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-asciidoc hljs&amp;quot; data-lang=&amp;quot;asciidoc&amp;quot;&amp;gt;* pass:[&amp;amp;lt;span style=&amp;quot;display:inline-block;width:1em;height:1em;background:#ffffff;border:3px solid #7952b3;vertical-align:middle;margin-right:0.5em&amp;quot;&amp;amp;gt;&amp;amp;lt;/span&amp;amp;gt;] Bordure violette&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_ソリューションアーキテクチャ&amp;quot;&amp;gt;ソリューションアーキテクチャ&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
package &amp;quot;ドキュメントワークフロー&amp;quot; {
  [Document AsciiDoc\navec pass macro] as asciidoc
  [Processeur JBake] as jbake
  [Site HTML statique] as html
  [Navigateur Web] as browser
}

asciidoc --&amp;amp;gt; jbake : 1. Compilation
jbake --&amp;amp;gt; html : 2. Génération
html --&amp;amp;gt; browser : 3. Affichage
browser --&amp;amp;gt; browser : 4. Rendu CSS

note right of asciidoc
  Contient les balises
  pass:[] avec HTML inline
end note

note right of jbake
  Préserve le HTML
  dans pass:[]
end note

note right of browser
  Applique les styles
  inline CSS
end note
@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_利点と制限&amp;quot;&amp;gt;利点と制限&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_利点&amp;quot;&amp;gt;利点&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;自律性 : 外部ファイルへの依存はありません&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;�✓ &amp;lt;strong&amp;gt;ポータビリティ&amp;lt;/strong&amp;gt; : すべての AsciiDoc プロセッサーで動作します&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;�✓ &amp;lt;strong&amp;gt;同期化&amp;lt;/strong&amp;gt; : カラーコードはHTMLに直接記述されています&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;�✓ &amp;lt;strong&amp;gt;柔軟性&amp;lt;/strong&amp;gt; : スタイルの完全なカスタマイズ&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;メンテナンス&amp;lt;/strong&amp;gt; : 16進コードの簡単な変更&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;✓ &amp;lt;strong&amp;gt;JBake 互換性&amp;lt;/strong&amp;gt; : 静的サイトジェネレーターと完全に互換性があります&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_制限&amp;quot;&amp;gt;制限&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;冗長&amp;lt;/strong&amp;gt; : HTMLコードの繰り返しは、AsciiDocソース内&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;✗ &amp;lt;strong&amp;gt;ソースの可読性&amp;lt;/strong&amp;gt; : ソースドキュメントはそれほどきれいではない&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;✗ &amp;lt;strong&amp;gt;アクセシビリティ&amp;lt;/strong&amp;gt; : ネイティブな代替テキストはありません（手動で追加する必要があります）&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_アクセシビリティの向上&amp;quot;&amp;gt;アクセシビリティの向上&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;スクリーンリーダーが読めるように四角をアクセシブルにする：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-asciidoc hljs&amp;quot; data-lang=&amp;quot;asciidoc&amp;quot;&amp;gt;* pass:[&amp;amp;lt;span role=&amp;quot;img&amp;quot; aria-label=&amp;quot;Couleur violet Bootstrap&amp;quot;
style=&amp;quot;display:inline-block;width:1em;height:1em;background:#7952b3;
vertical-align:middle;margin-right:0.5em&amp;quot;&amp;amp;gt;&amp;amp;lt;/span&amp;amp;gt;]
--accent-color: `#7952b3` (violet Bootstrap)&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;属性`role=&amp;quot;img&amp;quot;` et `aria-label`補助技術が視覚コンテンツを理解し、説明できるようにします。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_具体例テーマのドキュメンテーション&amp;quot;&amp;gt;具体例：テーマのドキュメンテーション&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;複数のテーマを文書化した完全な例 :&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-asciidoc hljs&amp;quot; data-lang=&amp;quot;asciidoc&amp;quot;&amp;gt;= Guide des couleurs de l&amp;#39;application

== Thème Clair (`:root`)

* pass:[&amp;amp;lt;span style=&amp;quot;display:inline-block;width:1em;height:1em;background:#f8f9fa;border:1px solid #ccc;vertical-align:middle;margin-right:0.5em&amp;quot;&amp;amp;gt;&amp;amp;lt;/span&amp;amp;gt;] --bg-primary: `#f8f9fa` (blanc cassé)
* pass:[&amp;amp;lt;span style=&amp;quot;display:inline-block;width:1em;height:1em;background:#212529;vertical-align:middle;margin-right:0.5em&amp;quot;&amp;amp;gt;&amp;amp;lt;/span&amp;amp;gt;] --text-primary: `#212529` (noir très foncé)
* pass:[&amp;amp;lt;span style=&amp;quot;display:inline-block;width:1em;height:1em;background:#7952b3;vertical-align:middle;margin-right:0.5em&amp;quot;&amp;amp;gt;&amp;amp;lt;/span&amp;amp;gt;] --accent-color: `#7952b3` (violet Bootstrap)

== Thème Sombre (`[data-bs-theme=&amp;quot;dark&amp;quot;]`)

* pass:[&amp;amp;lt;span style=&amp;quot;display:inline-block;width:1em;height:1em;background:#212529;vertical-align:middle;margin-right:0.5em&amp;quot;&amp;amp;gt;&amp;amp;lt;/span&amp;amp;gt;] --bg-primary: `#212529` (noir très foncé)
* pass:[&amp;amp;lt;span style=&amp;quot;display:inline-block;width:1em;height:1em;background:#ffffff;border:1px solid #999;vertical-align:middle;margin-right:0.5em&amp;quot;&amp;amp;gt;&amp;amp;lt;/span&amp;amp;gt;] --text-primary: `#ffffff` (blanc)
* pass:[&amp;amp;lt;span style=&amp;quot;display:inline-block;width:1em;height:1em;background:#0d6efd;vertical-align:middle;margin-right:0.5em&amp;quot;&amp;amp;gt;&amp;amp;lt;/span&amp;amp;gt;] --accent-color: `#0d6efd` (bleu Bootstrap)

== Thème Contraste Élevé (`[data-bs-theme=&amp;quot;high-contrast&amp;quot;]`)

* pass:[&amp;amp;lt;span style=&amp;quot;display:inline-block;width:1em;height:1em;background:#000000;vertical-align:middle;margin-right:0.5em&amp;quot;&amp;amp;gt;&amp;amp;lt;/span&amp;amp;gt;] --bg-primary: `#000000` (noir)
* pass:[&amp;amp;lt;span style=&amp;quot;display:inline-block;width:1em;height:1em;background:#ffffff;border:1px solid #000;vertical-align:middle;margin-right:0.5em&amp;quot;&amp;amp;gt;&amp;amp;lt;/span&amp;amp;gt;] --text-primary: `#ffffff` (blanc)
* pass:[&amp;amp;lt;span style=&amp;quot;display:inline-block;width:1em;height:1em;background:#00ff00;vertical-align:middle;margin-right:0.5em&amp;quot;&amp;amp;gt;&amp;amp;lt;/span&amp;amp;gt;] --accent-color: `#00ff00` (vert vif)&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_結論&amp;quot;&amp;gt;結論&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;マクロを介したHTMLインジェクション``AsciiDocは、技術文書で色見本を表示するためのエレガントで実用的なソリューションを提供します。やや冗長ではあるが、このアプローチは最大限の移植性と簡素化されたメンテナンスを保証します。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;この技術は外部の設定や追加のスタイルシートを必要とせず、JBakeおよびすべての標準的なAsciiDocプロセッサとすぐに動作します。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;最初の色付きの正方形を作成したら、HTMLコードをコピー＆ペーストし、16進数コードを変更するだけで、すぐに完全なパレットを作成できます。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;この技術は、カスタマイズされたビジュアルレンダリングを必要とする他のユースケースにも拡張できます：アイコン、バッジ、シンプルなグラフ、またはスタイルを正確に制御する必要のあるすべてのビジュアル要素。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_リソース&amp;quot;&amp;gt;リソース&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;https://docs.asciidoctor.org/asciidoc/latest/pass/pass-macro/&amp;quot; target=&amp;quot;_blank&amp;quot; rel=&amp;quot;noopener&amp;quot;&amp;gt;AsciiDoc ドキュメント : pass macro&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;https://jbake.org/docs/2.6.7/&amp;quot; target=&amp;quot;_blank&amp;quot; rel=&amp;quot;noopener&amp;quot;&amp;gt;JBakeドキュメンテーション&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;https://developer.mozilla.org/fr/docs/Web/CSS/color_value&amp;quot; target=&amp;quot;_blank&amp;quot; rel=&amp;quot;noopener&amp;quot;&amp;gt;MDN : CSSのカラー値&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;em&amp;gt;掲載された記事 2025-11-01&amp;lt;/em&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;</description>
        </item><item>
            <title>Thymeleaf を使用した JBake 静的サイトの国際化</title>
            <link >https://cheroliv.com/blog/2025/0095_i18n-site-statique-jbake-thymeleaf_post.html</link>
            <pubDate>Mon, 20 Oct 2025 00:00:00 +0000</pubDate>
            <guid isPermaLink="false">blog/2025/0095_i18n-site-statique-jbake-thymeleaf_post.html</guid>
            <description>&amp;lt;div id=&amp;quot;toc&amp;quot; class=&amp;quot;toc&amp;quot;&amp;gt;
&amp;lt;div id=&amp;quot;toctitle&amp;quot;&amp;gt;Table of Contents&amp;lt;/div&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel1&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_はじめに&amp;quot;&amp;gt;はじめに&amp;lt;/a&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel2&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_ユースケース図_use_case&amp;quot;&amp;gt;ユースケース図 (Use Case)&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_国際化のアーキテクチャ&amp;quot;&amp;gt;国際化のアーキテクチャ&amp;lt;/a&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel2&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_構造図ファイル構成&amp;quot;&amp;gt;構造図（ファイル構成）&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_なぜこのアプローチ&amp;quot;&amp;gt;なぜこのアプローチ？&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_コンポーネント図&amp;quot;&amp;gt;コンポーネント図&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_thymeleafを使用したテンプレートの国際化&amp;quot;&amp;gt;Thymeleafを使用したテンプレートの国際化&amp;lt;/a&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel2&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_メッセージファイルの構造&amp;quot;&amp;gt;メッセージファイルの構造&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_メッセージファイルの内容&amp;quot;&amp;gt;メッセージファイルの内容&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_テンプレートでの使用&amp;quot;&amp;gt;テンプレートでの使用&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_シーケンス図_i18nの解決&amp;quot;&amp;gt;シーケンス図 - i18nの解決&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_jbakeにおけるロケールの設定&amp;quot;&amp;gt;JBakeにおけるロケールの設定&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_記事の国際化フォルダーごとの整理&amp;quot;&amp;gt;記事の国際化：フォルダーごとの整理&amp;lt;/a&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel2&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_フローチャート_flow_生成&amp;quot;&amp;gt;フローチャート (Flow) - 生成&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_フォルダ構造&amp;quot;&amp;gt;フォルダ構造&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_このアプローチの利点&amp;quot;&amp;gt;このアプローチの利点&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_記事のメタデータ&amp;quot;&amp;gt;記事のメタデータ&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_urlの設定&amp;quot;&amp;gt;URLの設定&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_多言語表示用テンプレート&amp;quot;&amp;gt;多言語表示用テンプレート&amp;lt;/a&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel2&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_言語セレクタ付き記事テンプレート&amp;quot;&amp;gt;言語セレクタ付き記事テンプレート&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_言語でフィルタリングされたインデックス&amp;quot;&amp;gt;言語でフィルタリングされたインデックス&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_言語間ナビゲーション&amp;quot;&amp;gt;言語間ナビゲーション&amp;lt;/a&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel2&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_グローバル言語セレクター&amp;quot;&amp;gt;グローバル言語セレクター&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_フローチャート_ユーザーによる読み取り&amp;quot;&amp;gt;フローチャート - ユーザーによる読み取り&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_セレクター用のcssスタイル&amp;quot;&amp;gt;セレクター用のCSSスタイル&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_言語別_rss_フィード&amp;quot;&amp;gt;言語別 RSS フィード&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_良いプラクティスとコツ&amp;quot;&amp;gt;良いプラクティスとコツ&amp;lt;/a&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel2&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_記事識別子の一貫性&amp;quot;&amp;gt;記事識別子の一貫性&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_2_一貫性のある日付&amp;quot;&amp;gt;2. 一貫性のある日付&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_3_多言語タグ&amp;quot;&amp;gt;3. 多言語タグ&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_4_未翻訳記事の管理&amp;quot;&amp;gt;4. 未翻訳記事の管理&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_5_多言語サイトマップ&amp;quot;&amp;gt;5. 多言語サイトマップ&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_結論&amp;quot;&amp;gt;結論&amp;lt;/a&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel2&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_配置図&amp;quot;&amp;gt;配置図&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_はじめに&amp;quot;&amp;gt;はじめに&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;静的サイトの国際化（i18n）は一見複雑に見えるかもしれませんが、JBakeとThymeleafを組み合わせることで、多言語サイトを作成するための洗練されたソリューションが提供されます。この記事では、私のブログでi18nをどのように実装したかを紹介し、テンプレートと複数言語での記事管理の両方をカバーします。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_ユースケース図_use_case&amp;quot;&amp;gt;ユースケース図 (Use Case)&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
left to right direction
skinparam packageStyle rectangle

actor &amp;quot;著者&amp;quot; as author
actor &amp;quot;リーダー FR&amp;quot; as reader_fr
actor &amp;quot;リーダー EN&amp;quot; as reader_en

rectangle &amp;quot;JBake多言語サイト&amp;quot; {
  usecase &amp;quot;FR記事を書く&amp;quot; as UC1
  usecase &amp;quot;記事をENで書く&amp;quot; as UC2
  usecase &amp;quot;i18nメッセージを設定する&amp;quot; as UC3
  usecase &amp;quot;サイト生成&amp;quot; as UC4
  usecase &amp;quot;FR記事を読む&amp;quot; as UC5
  usecase &amp;quot;記事を読む EN&amp;quot; as UC6
  usecase &amp;quot;言語を変更&amp;quot; as UC7
  usecase &amp;quot;利用可能な翻訳を見る&amp;quot; as UC8
}

author --&amp;amp;gt; UC1
author --&amp;amp;gt; UC2
author --&amp;amp;gt; UC3
author --&amp;amp;gt; UC4

reader_fr --&amp;amp;gt; UC5
reader_fr --&amp;amp;gt; UC7
reader_fr --&amp;amp;gt; UC8

reader_en --&amp;amp;gt; UC6
reader_en --&amp;amp;gt; UC7
reader_en --&amp;amp;gt; UC8

UC1 ..&amp;amp;gt; UC4 : &amp;amp;lt;&amp;amp;lt;include&amp;amp;gt;&amp;amp;gt;
UC2 ..&amp;amp;gt; UC4 : &amp;amp;lt;&amp;amp;lt;include&amp;amp;gt;&amp;amp;gt;
UC3 ..&amp;amp;gt; UC4 : &amp;amp;lt;&amp;amp;lt;include&amp;amp;gt;&amp;amp;gt;
UC5 ..&amp;amp;gt; UC8 : &amp;amp;lt;&amp;amp;lt;extend&amp;amp;gt;&amp;amp;gt;
UC6 ..&amp;amp;gt; UC8 : &amp;amp;lt;&amp;amp;lt;extend&amp;amp;gt;&amp;amp;gt;
@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_国際化のアーキテクチャ&amp;quot;&amp;gt;国際化のアーキテクチャ&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;私たちのアプローチは2つの柱に基づいています：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;olist arabic&amp;quot;&amp;gt;
&amp;lt;ol class=&amp;quot;arabic&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;テンプレートのi18n&amp;lt;/strong&amp;gt;: インターフェース要素用のThymeleafメッセージファイルの使用&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;コンテンツの i18n&amp;lt;/strong&amp;gt;言語ごとに記事を整理するための専用フォルダ構造&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ol&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_構造図ファイル構成&amp;quot;&amp;gt;構造図（ファイル構成）&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
@startsalt
{
{T
+ projet-jbake
++ content
+++ blog
++++ 2024
+++++ fr
++++++ article1.adoc
++++++ article2.adoc
+++++ en
++++++ article1.adoc
++++++ article2.adoc
++++ 2025
+++++ fr
++++++ guide-i18n.adoc
+++++ en
++++++ i18n-guide.adoc
++ templates
+++ post.html
+++ index.html
+++ index_en.html
+++ messages.properties
+++ messages_fr.properties
+++ messages_en.properties
++ assets
+++ css
+++ js
+++ img
++ jbake.properties
++ output
+++ fr
++++ blog
+++++ 2025
++++++ guide-i18n.html
+++ en
++++ blog
+++++ 2025
++++++ i18n-guide.html
}
}
@endsalt
@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_なぜこのアプローチ&amp;quot;&amp;gt;なぜこのアプローチ？&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;この分離により、以下のことが可能になります :&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;言語に関わらず、インターフェースの一貫性を維持する&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;コンテンツと記事の翻訳を独立して管理する&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;新しい言語の追加を大規模なリファクタリングなしで容易にする&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;特定の言語でのみ利用可能な記事を許可する&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_コンポーネント図&amp;quot;&amp;gt;コンポーネント図&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
skinparam componentStyle rectangle

package &amp;quot;出典&amp;quot; {
  folder &amp;quot;content/blog/2025/&amp;quot; {
    folder &amp;quot;fr/&amp;quot; as content_fr {
      [article1.adoc]
      [article2.adoc]
    }
    folder &amp;quot;en/&amp;quot; as content_en {
      [article1.adoc] as article1_en
      [article2.adoc] as article2_en
    }
  }

  folder &amp;quot;テンプレート/&amp;quot; {
    [post.html]
    [index.html]
    [index_en.html]
  }

  folder &amp;quot;メッセージ/&amp;quot; {
    [messages_fr.properties]
    [messages_en.properties]
  }

  [jbake.properties]
}

package &amp;quot;JBake エンジン&amp;quot; {
  [Parser AsciiDoc] as parser
  [Template Engine\nThymeleaf] as thymeleaf
  [Generator] as generator
  [I18n Resolver] as i18n
}

package &amp;quot;生成されたサイト&amp;quot; {
  folder &amp;quot;fr/&amp;quot; {
    folder &amp;quot;ブログ/2025/&amp;quot; as blog_fr {
      [article1.html]
      [article2.html]
    }
  }

  folder &amp;quot;en/&amp;quot; {
    folder &amp;quot;ブログ/2025/&amp;quot; as blog_en {
      [article1.html] as article1_html_en
      [article2.html] as article2_html_en
    }
  }
}

content_fr --&amp;amp;gt; parser
content_en --&amp;amp;gt; parser
parser --&amp;amp;gt; generator

templates --&amp;amp;gt; thymeleaf
messages --&amp;amp;gt; i18n
i18n --&amp;amp;gt; thymeleaf
thymeleaf --&amp;amp;gt; generator
jbake.properties --&amp;amp;gt; generator

generator --&amp;amp;gt; blog_fr
generator --&amp;amp;gt; blog_en
@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_thymeleafを使用したテンプレートの国際化&amp;quot;&amp;gt;Thymeleafを使用したテンプレートの国際化&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_メッセージファイルの構造&amp;quot;&amp;gt;メッセージファイルの構造&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;最初の手順は、サポートされている各言語用のプロパティファイルを作成することです：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-text hljs&amp;quot; data-lang=&amp;quot;text&amp;quot;&amp;gt;src/jbake/templates/
├── messages.properties        # Fallback par défaut
├── messages_fr.properties     # Français
├── messages_en.properties     # Anglais
└── messages_de.properties     # Allemand&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_メッセージファイルの内容&amp;quot;&amp;gt;メッセージファイルの内容&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;ファイルの例です`messages_fr.properties`:&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-properties hljs&amp;quot; data-lang=&amp;quot;properties&amp;quot;&amp;gt;# Navigation
nav.home=Accueil
nav.blog=Blog
nav.about=À propos
nav.contact=Contact

# Articles
article.readmore=Lire la suite
article.published=Publié le
article.tags=Étiquettes
article.also.available=Également disponible en

# Interface
site.title=Mon Blog Technique
site.description=Partage de connaissances et expériences
footer.copyright=© 2025 Tous droits réservés
search.placeholder=Rechercher un article...&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;そしてその英語訳`messages_en.properties`:&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-properties hljs&amp;quot; data-lang=&amp;quot;properties&amp;quot;&amp;gt;# Navigation
nav.home=Home
nav.blog=Blog
nav.about=About
nav.contact=Contact

# Articles
article.readmore=Read more
article.published=Published on
article.tags=Tags
article.also.available=Also available in

# Interface
site.title=My Tech Blog
site.description=Sharing knowledge and experiences
footer.copyright=© 2025 All rights reserved
search.placeholder=Search articles...&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_テンプレートでの使用&amp;quot;&amp;gt;テンプレートでの使用&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;Thymeleafのテンプレートでは、構文を使ってください`#{}`メッセージにアクセスする:&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-html hljs&amp;quot; data-lang=&amp;quot;html&amp;quot;&amp;gt;&amp;amp;lt;!DOCTYPE html&amp;amp;gt;
&amp;amp;lt;html xmlns:th=&amp;quot;http://www.thymeleaf.org&amp;quot;&amp;amp;gt;
&amp;amp;lt;head&amp;amp;gt;
    &amp;amp;lt;title th:text=&amp;quot;#{site.title}&amp;quot;&amp;amp;gt;Mon Blog&amp;amp;lt;/title&amp;amp;gt;
    &amp;amp;lt;meta name=&amp;quot;description&amp;quot; th:content=&amp;quot;#{site.description}&amp;quot; /&amp;amp;gt;
&amp;amp;lt;/head&amp;amp;gt;
&amp;amp;lt;body&amp;amp;gt;
    &amp;amp;lt;nav&amp;amp;gt;
        &amp;amp;lt;a th:href=&amp;quot;@{/}&amp;quot; th:text=&amp;quot;#{nav.home}&amp;quot;&amp;amp;gt;Accueil&amp;amp;lt;/a&amp;amp;gt;
        &amp;amp;lt;a th:href=&amp;quot;@{/blog/}&amp;quot; th:text=&amp;quot;#{nav.blog}&amp;quot;&amp;amp;gt;Blog&amp;amp;lt;/a&amp;amp;gt;
        &amp;amp;lt;a th:href=&amp;quot;@{/about.html}&amp;quot; th:text=&amp;quot;#{nav.about}&amp;quot;&amp;amp;gt;À propos&amp;amp;lt;/a&amp;amp;gt;
    &amp;amp;lt;/nav&amp;amp;gt;

    &amp;amp;lt;footer&amp;amp;gt;
        &amp;amp;lt;p th:text=&amp;quot;#{footer.copyright}&amp;quot;&amp;amp;gt;Copyright&amp;amp;lt;/p&amp;amp;gt;
    &amp;amp;lt;/footer&amp;amp;gt;
&amp;amp;lt;/body&amp;amp;gt;
&amp;amp;lt;/html&amp;amp;gt;&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_シーケンス図_i18nの解決&amp;quot;&amp;gt;シーケンス図 - i18nの解決&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
actor Auteur
participant JBake
participant &amp;quot;AsciiDoc
パーサー&amp;quot; as parser
participant &amp;quot;Thymeleaf\nエンジン&amp;quot; as thymeleaf
participant &amp;quot;I18n
リゾルバー&amp;quot; as i18n
database &amp;quot;messages_*.properties&amp;quot; as messages

Auteur -&amp;amp;gt; JBake: jbake -b
activate JBake

JBake -&amp;amp;gt; parser: Lire article.fr.adoc
activate parser
parser --&amp;amp;gt; JBake: Contenu + métadonnées\n(lang=fr, article-id=xyz)
deactivate parser

JBake -&amp;amp;gt; parser: Lire article.en.adoc
activate parser
parser --&amp;amp;gt; JBake: Contenu + métadonnées\n(lang=en, article-id=xyz)
deactivate parser

JBake -&amp;amp;gt; thymeleaf: Générer page FR
activate thymeleaf

thymeleaf -&amp;amp;gt; i18n: Résoudre #{nav.home}
activate i18n
i18n -&amp;amp;gt; messages: Lire messages_fr.properties
messages --&amp;amp;gt; i18n: &amp;quot;ホーム&amp;quot;
i18n --&amp;amp;gt; thymeleaf: &amp;quot;ホーム&amp;quot;
deactivate i18n

thymeleaf -&amp;amp;gt; JBake: Rechercher traductions\n(article-id=xyz, lang!=fr)
JBake --&amp;amp;gt; thymeleaf: article.en.html trouvé

thymeleaf --&amp;amp;gt; JBake: /fr/blog/article.html
deactivate thymeleaf

JBake -&amp;amp;gt; thymeleaf: Générer page EN
activate thymeleaf

thymeleaf -&amp;amp;gt; i18n: Résoudre #{nav.home}
activate i18n
i18n -&amp;amp;gt; messages: Lire messages_en.properties
messages --&amp;amp;gt; i18n: &amp;quot;家&amp;quot;
i18n --&amp;amp;gt; thymeleaf: &amp;quot;家&amp;quot;
deactivate i18n

thymeleaf -&amp;amp;gt; JBake: Rechercher traductions\n(article-id=xyz, lang!=en)
JBake --&amp;amp;gt; thymeleaf: article.fr.html trouvé

thymeleaf --&amp;amp;gt; JBake: /en/blog/article.html
deactivate thymeleaf

JBake --&amp;amp;gt; Auteur: Site généré
deactivate JBake
@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_jbakeにおけるロケールの設定&amp;quot;&amp;gt;JBakeにおけるロケールの設定&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;あなたのファイルで`jbake.properties`, デフォルトロケールを設定してください :&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-properties hljs&amp;quot; data-lang=&amp;quot;properties&amp;quot;&amp;gt;# Locale par défaut
thymeleaf.locale=fr

# Encodage
template.encoding=UTF-8&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_記事の国際化フォルダーごとの整理&amp;quot;&amp;gt;記事の国際化：フォルダーごとの整理&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_フローチャート_flow_生成&amp;quot;&amp;gt;フローチャート (Flow) - 生成&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
start

:Lire jbake.properties;
:Charger configuration i18n;

partition &amp;quot;各AsciiDocファイルごとに&amp;quot; {
  :Lire métadonnées\n(:jbake-lang:, :jbake-article-id:);
  :Parser contenu AsciiDoc;
  :Stocker en mémoire avec langue;
}

partition &amp;quot;各テンプレートに対して&amp;quot; {
  :Charger template Thymeleaf;
  :Identifier langue cible;
  :Charger messages_{lang}.properties;

  partition &amp;quot;コンテンツフィルタリング&amp;quot; {
    :Filtrer articles par langue;
    :Grouper traductions\npar article-id;
  }

  :Appliquer template avec i18n;
  :Générer HTML dans /{lang}/;
}

:Copier assets statiques;
:Générer sitemap multilingue;
:Générer flux RSS par langue;

stop
@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_フォルダ構造&amp;quot;&amp;gt;フォルダ構造&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;ファイル名にサフィックスを使用する代わりに、フォルダによる整理を選択しました：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-text hljs&amp;quot; data-lang=&amp;quot;text&amp;quot;&amp;gt;content/blog/
├── 2024/
│   ├── fr/
│   │   ├── introduction-jbake.adoc
│   │   ├── guide-thymeleaf.adoc
│   │   └── astuces-asciidoc.adoc
│   └── en/
│       ├── introduction-jbake.adoc
│       ├── thymeleaf-guide.adoc
│       └── asciidoc-tips.adoc
└── 2025/
    ├── fr/
    │   └── internationalisation-jbake.adoc
    └── en/
        └── jbake-internationalization.adoc&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_このアプローチの利点&amp;quot;&amp;gt;このアプローチの利点&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;この構造にはいくつかの利点があります：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;明確な分離&amp;lt;/strong&amp;gt;各言語には独自のスペースがあります&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;�柔軟な命名&amp;lt;/strong&amp;gt;: ファイルは言語によって異なる名前になる可能性があります&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;スケーラビリティ&amp;lt;/strong&amp;gt;新しい言語を追加するのが簡単&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;自然な組織&amp;lt;/strong&amp;gt;: JBakeの時間的論理に従う&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_記事のメタデータ&amp;quot;&amp;gt;記事のメタデータ&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;各記事は翻訳間のリンクを可能にするためにメタデータを含まなければなりません。以下に例を示します：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;フランス語版&amp;lt;/strong&amp;gt;(&amp;lt;code&amp;gt;2025/fr/internationalisation-jbake.adoc&amp;lt;/code&amp;gt;) :&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-asciidoc hljs&amp;quot; data-lang=&amp;quot;asciidoc&amp;quot;&amp;gt;= Internationalisation d&amp;#39;un site statique JBake
:jbake-type: post
:jbake-status: published
:jbake-date: 2025-10-20
:jbake-lang: fr
:jbake-article-id: jbake-i18n-thymeleaf
:jbake-tags: jbake, thymeleaf, i18n
:jbake-description: Guide pour mettre en place l&amp;#39;i18n avec JBake&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;英語版&amp;lt;/strong&amp;gt;(&amp;lt;code&amp;gt;2025/en/jbake-internationalization.adoc&amp;lt;/code&amp;gt;) :&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-asciidoc hljs&amp;quot; data-lang=&amp;quot;asciidoc&amp;quot;&amp;gt;= Internationalizing a JBake Static Site
:jbake-type: post
:jbake-status: published
:jbake-date: 2025-10-20
:jbake-lang: en
:jbake-article-id: jbake-i18n-thymeleaf
:jbake-tags: jbake, thymeleaf, i18n
:jbake-description: Guide to implement i18n with JBake&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;属性`:jbake-article-id:`は重要です：それは、同じ記事のさまざまな訳を結びつけることを可能にします。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_urlの設定&amp;quot;&amp;gt;URLの設定&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;中に`jbake.properties`, URLパターンを言語を含むように設定してください :&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-properties hljs&amp;quot; data-lang=&amp;quot;properties&amp;quot;&amp;gt;# Pattern d&amp;#39;URL avec langue
post.permalink.pattern=:lang/blog/:year/:name.html

# Langue par défaut
site.default.lang=fr&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;これにより、次のような URL が生成されます：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;code&amp;gt;/fr/blog/2025/internationalisation-jbake.html&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;code&amp;gt;/en/blog/2025/jbake-internationalization.html&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_多言語表示用テンプレート&amp;quot;&amp;gt;多言語表示用テンプレート&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_言語セレクタ付き記事テンプレート&amp;quot;&amp;gt;言語セレクタ付き記事テンプレート&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;テンプレートを作成してください`post.html`利用可能な翻訳を表示します :&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-html hljs&amp;quot; data-lang=&amp;quot;html&amp;quot;&amp;gt;&amp;amp;lt;!DOCTYPE html&amp;amp;gt;
&amp;amp;lt;html xmlns:th=&amp;quot;http://www.thymeleaf.org&amp;quot;&amp;amp;gt;
&amp;amp;lt;head&amp;amp;gt;
    &amp;amp;lt;title th:text=&amp;quot;${content.title}&amp;quot;&amp;amp;gt;Article&amp;amp;lt;/title&amp;amp;gt;
&amp;amp;lt;/head&amp;amp;gt;
&amp;amp;lt;body&amp;amp;gt;
    &amp;amp;lt;article&amp;amp;gt;
        &amp;amp;lt;header&amp;amp;gt;
            &amp;amp;lt;h1 th:text=&amp;quot;${content.title}&amp;quot;&amp;amp;gt;Titre&amp;amp;lt;/h1&amp;amp;gt;

            &amp;amp;lt;div class=&amp;quot;article-meta&amp;quot;&amp;amp;gt;
                &amp;amp;lt;time th:text=&amp;quot;${#dates.format(content.date, &amp;#39;dd MMMM yyyy&amp;#39;)}&amp;quot;
                      th:attr=&amp;quot;datetime=${#dates.format(content.date, &amp;#39;yyyy-MM-dd&amp;#39;)}&amp;quot;&amp;amp;gt;
                    Date
                &amp;amp;lt;/time&amp;amp;gt;

                &amp;amp;lt;!-- Sélecteur de traductions --&amp;amp;gt;
                &amp;amp;lt;div class=&amp;quot;translations&amp;quot; th:if=&amp;quot;${content[&amp;#39;article-id&amp;#39;]}&amp;quot;&amp;amp;gt;
                    &amp;amp;lt;span th:text=&amp;quot;#{article.also.available}&amp;quot;&amp;amp;gt;Aussi disponible en :&amp;amp;lt;/span&amp;amp;gt;
                    &amp;amp;lt;ul class=&amp;quot;language-list&amp;quot;&amp;amp;gt;
                        &amp;amp;lt;li th:each=&amp;quot;post : ${published_posts}&amp;quot;
                            th:if=&amp;quot;${post[&amp;#39;article-id&amp;#39;] == content[&amp;#39;article-id&amp;#39;] and post.lang != content.lang}&amp;quot;&amp;amp;gt;
                            &amp;amp;lt;a th:href=&amp;quot;${post.uri}&amp;quot;
                               th:text=&amp;quot;${post.lang.toUpperCase()}&amp;quot;&amp;amp;gt;
                                LANG
                            &amp;amp;lt;/a&amp;amp;gt;
                        &amp;amp;lt;/li&amp;amp;gt;
                    &amp;amp;lt;/ul&amp;amp;gt;
                &amp;amp;lt;/div&amp;amp;gt;
            &amp;amp;lt;/div&amp;amp;gt;
        &amp;amp;lt;/header&amp;amp;gt;

        &amp;amp;lt;div class=&amp;quot;content&amp;quot; th:utext=&amp;quot;${content.body}&amp;quot;&amp;amp;gt;
            Contenu de l&amp;#39;article
        &amp;amp;lt;/div&amp;amp;gt;

        &amp;amp;lt;footer class=&amp;quot;article-footer&amp;quot;&amp;amp;gt;
            &amp;amp;lt;div class=&amp;quot;tags&amp;quot; th:if=&amp;quot;${content.tags}&amp;quot;&amp;amp;gt;
                &amp;amp;lt;span th:text=&amp;quot;#{article.tags}&amp;quot;&amp;amp;gt;Étiquettes :&amp;amp;lt;/span&amp;amp;gt;
                &amp;amp;lt;span th:each=&amp;quot;tag : ${content.tags}&amp;quot;&amp;amp;gt;
                    &amp;amp;lt;a th:href=&amp;quot;@{/tags/{tag}.html(tag=${tag})}&amp;quot;
                       th:text=&amp;quot;${tag}&amp;quot;&amp;amp;gt;tag&amp;amp;lt;/a&amp;amp;gt;
                &amp;amp;lt;/span&amp;amp;gt;
            &amp;amp;lt;/div&amp;amp;gt;
        &amp;amp;lt;/footer&amp;amp;gt;
    &amp;amp;lt;/article&amp;amp;gt;
&amp;amp;lt;/body&amp;amp;gt;
&amp;amp;lt;/html&amp;amp;gt;&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_言語でフィルタリングされたインデックス&amp;quot;&amp;gt;言語でフィルタリングされたインデックス&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;各言語向けのインデックステンプレートを作成してください：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;index.html&amp;lt;/strong&amp;gt;(フランス語インデックス) :&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-html hljs&amp;quot; data-lang=&amp;quot;html&amp;quot;&amp;gt;&amp;amp;lt;!DOCTYPE html&amp;amp;gt;
&amp;amp;lt;html xmlns:th=&amp;quot;http://www.thymeleaf.org&amp;quot;&amp;amp;gt;
&amp;amp;lt;head&amp;amp;gt;
    &amp;amp;lt;title th:text=&amp;quot;#{site.title}&amp;quot;&amp;amp;gt;Mon Blog&amp;amp;lt;/title&amp;amp;gt;
&amp;amp;lt;/head&amp;amp;gt;
&amp;amp;lt;body&amp;amp;gt;
    &amp;amp;lt;main&amp;amp;gt;
        &amp;amp;lt;h1 th:text=&amp;quot;#{nav.blog}&amp;quot;&amp;amp;gt;Blog&amp;amp;lt;/h1&amp;amp;gt;

        &amp;amp;lt;div class=&amp;quot;articles-list&amp;quot;&amp;amp;gt;
            &amp;amp;lt;article th:each=&amp;quot;post : ${published_posts}&amp;quot;
                     th:if=&amp;quot;${post.lang == &amp;#39;fr&amp;#39;}&amp;quot;&amp;amp;gt;
                &amp;amp;lt;h2&amp;amp;gt;
                    &amp;amp;lt;a th:href=&amp;quot;${post.uri}&amp;quot; th:text=&amp;quot;${post.title}&amp;quot;&amp;amp;gt;Titre&amp;amp;lt;/a&amp;amp;gt;
                &amp;amp;lt;/h2&amp;amp;gt;
                &amp;amp;lt;time th:text=&amp;quot;${#dates.format(post.date, &amp;#39;dd MMMM yyyy&amp;#39;)}&amp;quot;&amp;amp;gt;
                    Date
                &amp;amp;lt;/time&amp;amp;gt;
                &amp;amp;lt;p th:text=&amp;quot;${post.description}&amp;quot;&amp;amp;gt;Description&amp;amp;lt;/p&amp;amp;gt;
                &amp;amp;lt;a th:href=&amp;quot;${post.uri}&amp;quot; th:text=&amp;quot;#{article.readmore}&amp;quot;&amp;amp;gt;
                    Lire la suite
                &amp;amp;lt;/a&amp;amp;gt;
            &amp;amp;lt;/article&amp;amp;gt;
        &amp;amp;lt;/div&amp;amp;gt;
    &amp;amp;lt;/main&amp;amp;gt;
&amp;amp;lt;/body&amp;amp;gt;
&amp;amp;lt;/html&amp;amp;gt;&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;index_en.html&amp;lt;/strong&amp;gt;(英語インデックス) :&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-html hljs&amp;quot; data-lang=&amp;quot;html&amp;quot;&amp;gt;&amp;amp;lt;!DOCTYPE html&amp;amp;gt;
&amp;amp;lt;html xmlns:th=&amp;quot;http://www.thymeleaf.org&amp;quot;&amp;amp;gt;
&amp;amp;lt;head&amp;amp;gt;
    &amp;amp;lt;title th:text=&amp;quot;#{site.title}&amp;quot;&amp;amp;gt;My Blog&amp;amp;lt;/title&amp;amp;gt;
&amp;amp;lt;/head&amp;amp;gt;
&amp;amp;lt;body&amp;amp;gt;
    &amp;amp;lt;main&amp;amp;gt;
        &amp;amp;lt;h1 th:text=&amp;quot;#{nav.blog}&amp;quot;&amp;amp;gt;Blog&amp;amp;lt;/h1&amp;amp;gt;

        &amp;amp;lt;div class=&amp;quot;articles-list&amp;quot;&amp;amp;gt;
            &amp;amp;lt;article th:each=&amp;quot;post : ${published_posts}&amp;quot;
                     th:if=&amp;quot;${post.lang == &amp;#39;en&amp;#39;}&amp;quot;&amp;amp;gt;
                &amp;amp;lt;h2&amp;amp;gt;
                    &amp;amp;lt;a th:href=&amp;quot;${post.uri}&amp;quot; th:text=&amp;quot;${post.title}&amp;quot;&amp;amp;gt;Title&amp;amp;lt;/a&amp;amp;gt;
                &amp;amp;lt;/h2&amp;amp;gt;
                &amp;amp;lt;time th:text=&amp;quot;${#dates.format(post.date, &amp;#39;dd MMMM yyyy&amp;#39;)}&amp;quot;&amp;amp;gt;
                    Date
                &amp;amp;lt;/time&amp;amp;gt;
                &amp;amp;lt;p th:text=&amp;quot;${post.description}&amp;quot;&amp;amp;gt;Description&amp;amp;lt;/p&amp;amp;gt;
                &amp;amp;lt;a th:href=&amp;quot;${post.uri}&amp;quot; th:text=&amp;quot;#{article.readmore}&amp;quot;&amp;amp;gt;
                    Read more
                &amp;amp;lt;/a&amp;amp;gt;
            &amp;amp;lt;/article&amp;amp;gt;
        &amp;amp;lt;/div&amp;amp;gt;
    &amp;amp;lt;/main&amp;amp;gt;
&amp;amp;lt;/body&amp;amp;gt;
&amp;amp;lt;/html&amp;amp;gt;&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_言語間ナビゲーション&amp;quot;&amp;gt;言語間ナビゲーション&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_グローバル言語セレクター&amp;quot;&amp;gt;グローバル言語セレクター&amp;lt;/h3&amp;gt;

&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_フローチャート_ユーザーによる読み取り&amp;quot;&amp;gt;フローチャート - ユーザーによる読み取り&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
start

:Utilisateur accède au site;

if (Langue préférée ?) then (FR)
  :Afficher /index.html;
  :Lister articles FR;
else (EN)
  :Afficher /en/index.html;
  :Lister articles EN;
endif

:Utilisateur clique sur article;

:Afficher article\navec métadonnées;

if (Traductions disponibles ?) then (oui)
  :Afficher sélecteur\nde traductions;

  if (Changement de langue ?) then (oui)
    :Rediriger vers\ntraduction;
    :Afficher article\ndans nouvelle langue;
  else (non)
    :Continuer lecture;
  endif
else (non)
  :Continuer lecture;
endif

stop
@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;メインテンプレートに言語セレクターを追加してください:&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-html hljs&amp;quot; data-lang=&amp;quot;html&amp;quot;&amp;gt;&amp;amp;lt;nav class=&amp;quot;language-switcher&amp;quot;&amp;amp;gt;
    &amp;amp;lt;a href=&amp;quot;/index.html&amp;quot;
       th:classappend=&amp;quot;${content.lang == &amp;#39;fr&amp;#39;} ? &amp;#39;active&amp;#39;&amp;quot;
       title=&amp;quot;Français&amp;quot;&amp;amp;gt;
        🇫🇷 FR
    &amp;amp;lt;/a&amp;amp;gt;
    &amp;amp;lt;a href=&amp;quot;/en/index.html&amp;quot;
       th:classappend=&amp;quot;${content.lang == &amp;#39;en&amp;#39;} ? &amp;#39;active&amp;#39;&amp;quot;
       title=&amp;quot;English&amp;quot;&amp;amp;gt;
        🇬🇧 EN
    &amp;amp;lt;/a&amp;amp;gt;
&amp;amp;lt;/nav&amp;amp;gt;&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_セレクター用のcssスタイル&amp;quot;&amp;gt;セレクター用のCSSスタイル&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-css hljs&amp;quot; data-lang=&amp;quot;css&amp;quot;&amp;gt;.language-switcher {
    display: flex;
    gap: 1rem;
    padding: 0.5rem;
    background: #f5f5f5;
    border-radius: 4px;
}

.language-switcher a {
    padding: 0.5rem 1rem;
    text-decoration: none;
    color: #333;
    border-radius: 4px;
    transition: background 0.2s;
}

.language-switcher a:hover {
    background: #e0e0e0;
}

.language-switcher a.active {
    background: #007bff;
    color: white;
}

.translations {
    margin: 1rem 0;
    padding: 1rem;
    background: #f8f9fa;
    border-left: 4px solid #007bff;
}

.language-list {
    display: inline-flex;
    gap: 0.5rem;
    list-style: none;
    padding: 0;
    margin: 0;
}

.language-list li::after {
    content: &amp;quot;•&amp;quot;;
    margin-left: 0.5rem;
}

.language-list li:last-child::after {
    content: &amp;quot;&amp;quot;;
}&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_言語別_rss_フィード&amp;quot;&amp;gt;言語別 RSS フィード&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;言語別にRSSフィードを分けるには、個別のテンプレートを作成してください：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;feed.xml&amp;lt;/strong&amp;gt;(フランス語のフラックス) :&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-xml hljs&amp;quot; data-lang=&amp;quot;xml&amp;quot;&amp;gt;&amp;amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot;?&amp;amp;gt;
&amp;amp;lt;rss version=&amp;quot;2.0&amp;quot; xmlns:th=&amp;quot;http://www.thymeleaf.org&amp;quot;&amp;amp;gt;
    &amp;amp;lt;channel&amp;amp;gt;
        &amp;amp;lt;title th:text=&amp;quot;#{site.title}&amp;quot;&amp;amp;gt;Mon Blog&amp;amp;lt;/title&amp;amp;gt;
        &amp;amp;lt;link th:text=&amp;quot;${config.site_host}&amp;quot;&amp;amp;gt;http://example.com&amp;amp;lt;/link&amp;amp;gt;
        &amp;amp;lt;description th:text=&amp;quot;#{site.description}&amp;quot;&amp;amp;gt;Description&amp;amp;lt;/description&amp;amp;gt;
        &amp;amp;lt;language&amp;amp;gt;fr&amp;amp;lt;/language&amp;amp;gt;

        &amp;amp;lt;item th:each=&amp;quot;post : ${published_posts}&amp;quot;
              th:if=&amp;quot;${post.lang == &amp;#39;fr&amp;#39;}&amp;quot;&amp;amp;gt;
            &amp;amp;lt;title th:text=&amp;quot;${post.title}&amp;quot;&amp;amp;gt;Titre&amp;amp;lt;/title&amp;amp;gt;
            &amp;amp;lt;link th:text=&amp;quot;${config.site_host + post.uri}&amp;quot;&amp;amp;gt;Lien&amp;amp;lt;/link&amp;amp;gt;
            &amp;amp;lt;pubDate th:text=&amp;quot;${#dates.format(post.date, &amp;#39;EEE, dd MMM yyyy HH:mm:ss Z&amp;#39;)}&amp;quot;&amp;amp;gt;
                Date
            &amp;amp;lt;/pubDate&amp;amp;gt;
            &amp;amp;lt;description th:text=&amp;quot;${post.description}&amp;quot;&amp;amp;gt;Description&amp;amp;lt;/description&amp;amp;gt;
        &amp;amp;lt;/item&amp;amp;gt;
    &amp;amp;lt;/channel&amp;amp;gt;
&amp;amp;lt;/rss&amp;amp;gt;&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_良いプラクティスとコツ&amp;quot;&amp;gt;良いプラクティスとコツ&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_記事識別子の一貫性&amp;quot;&amp;gt;記事識別子の一貫性&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;必ず…してください`:jbake-article-id:`すべての同じ記事の翻訳に対して同じです。一貫したフォーマットを使用してください :&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;普遍性のために英語の識別子を使用してください&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;単語を区切るためにハイフンを使用してください&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;特殊文字を避けてください&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_2_一貫性のある日付&amp;quot;&amp;gt;2. 一貫性のある日付&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;記事のすべての翻訳は、同じ公開日である必要があります (&amp;lt;code&amp;gt;:jbake-date:&amp;lt;/code&amp;gt;). これは並び替えと時系列表示を容易にします。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_3_多言語タグ&amp;quot;&amp;gt;3. 多言語タグ&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;タグについては、2つのオプションがあります。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;オプション1 : 英語の普遍的なタグ&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-asciidoc hljs&amp;quot; data-lang=&amp;quot;asciidoc&amp;quot;&amp;gt;:jbake-tags: java, spring-boot, microservices&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;オプション2: マッピングを使ってタグを翻訳&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-asciidoc hljs&amp;quot; data-lang=&amp;quot;asciidoc&amp;quot;&amp;gt;# Version française
:jbake-tags: java, spring-boot, microservices

# Version anglaise
:jbake-tags: java, spring-boot, microservices&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_4_未翻訳記事の管理&amp;quot;&amp;gt;4. 未翻訳記事の管理&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;すべての記事を訳す必要はありません。ある記事が一方の言語だけに存在する場合、他方の言語のリストには表示されません。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_5_多言語サイトマップ&amp;quot;&amp;gt;5. 多言語サイトマップ&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;すべての言語を含むサイトマップを生成してください :&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-xml hljs&amp;quot; data-lang=&amp;quot;xml&amp;quot;&amp;gt;&amp;amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot;?&amp;amp;gt;
&amp;amp;lt;urlset xmlns=&amp;quot;http://www.sitemaps.org/schemas/sitemap/0.9&amp;quot;
        xmlns:xhtml=&amp;quot;http://www.w3.org/1999/xhtml&amp;quot;
        xmlns:th=&amp;quot;http://www.thymeleaf.org&amp;quot;&amp;amp;gt;
    &amp;amp;lt;url th:each=&amp;quot;post : ${published_posts}&amp;quot;&amp;amp;gt;
        &amp;amp;lt;loc th:text=&amp;quot;${config.site_host + post.uri}&amp;quot;&amp;amp;gt;URL&amp;amp;lt;/loc&amp;amp;gt;
        &amp;amp;lt;lastmod th:text=&amp;quot;${#dates.format(post.date, &amp;#39;yyyy-MM-dd&amp;#39;)}&amp;quot;&amp;amp;gt;Date&amp;amp;lt;/lastmod&amp;amp;gt;

        &amp;amp;lt;!-- Liens alternatifs pour les traductions --&amp;amp;gt;
        &amp;amp;lt;xhtml:link th:each=&amp;quot;translation : ${published_posts}&amp;quot;
                    th:if=&amp;quot;${translation[&amp;#39;article-id&amp;#39;] == post[&amp;#39;article-id&amp;#39;] and translation.lang != post.lang}&amp;quot;
                    rel=&amp;quot;alternate&amp;quot;
                    th:attr=&amp;quot;hreflang=${translation.lang},href=${config.site_host + translation.uri}&amp;quot; /&amp;amp;gt;
    &amp;amp;lt;/url&amp;amp;gt;
&amp;amp;lt;/urlset&amp;amp;gt;&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_結論&amp;quot;&amp;gt;結論&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;JBakeとThymeleafを使用したサイトの国際化は、堅牢で保守しやすいアプローチです。テンプレート（メッセージファイルを通じて）とコンテンツ（フォルダ構成を通じて）の国際化を分離することで、柔軟で容易に拡張できるシステムを得ることができます。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;覚えておくべき重要なポイント :&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;Thymeleafメッセージファイル&amp;lt;/strong&amp;gt;ユーザーインターフェイスのために&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;フォルダ別の整理&amp;lt;/strong&amp;gt;(年/言語) の記事&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;記事ID&amp;lt;/strong&amp;gt;翻訳をリンクするために&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;�専用テンプレート&amp;lt;/strong&amp;gt;各言語に対して&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;明示的なURL&amp;lt;/strong&amp;gt;言語コードを含む&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_配置図&amp;quot;&amp;gt;配置図&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
node &amp;quot;開発マシン&amp;quot; {
  artifact &amp;quot;ソース&amp;quot; {
    folder &amp;quot;コンテンツ/&amp;quot;
    folder &amp;quot;テンプレート/&amp;quot;
    folder &amp;quot;assets/&amp;quot;
  }

  component &amp;quot;JBake CLI&amp;quot; as jbake

  Sources --&amp;amp;gt; jbake : jbake -b
}

node &amp;quot;ビルドサーバー
(CI/CD)&amp;quot; {
  component &amp;quot;GitHub Actions
または GitLab CI&amp;quot; as ci

  jbake --&amp;amp;gt; ci : push
}

cloud &amp;quot;CDN / ホスティング&amp;quot; {
  node &amp;quot;静的Webサーバー&amp;quot; {
    artifact &amp;quot;生成されたサイト&amp;quot; {
      folder &amp;quot;/fr/blog/&amp;quot;
      folder &amp;quot;/en/blog/&amp;quot;
      folder &amp;quot;/assets/&amp;quot;
    }
  }
}

ci --&amp;amp;gt; &amp;quot;生成されたサイト&amp;quot; : déploiement

actor &amp;quot;読者&amp;quot; as users

users --&amp;amp;gt; &amp;quot;静的Webサーバー&amp;quot; : HTTPS
@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;このアーキテクチャは、2つの言語でシンプルに始められ、大規模なリファクタリングなしに他の言語を追加することもできます。全体は完全に静的で高性能であり、JBakeの哲学に忠実です。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;良い多言語開発！ 🌍&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;</description>
        </item><item>
            <title>UbuntuでTor Browserをインストールして確認する</title>
            <link >https://cheroliv.com/blog/2025/0094_tor_browser_install_post.html</link>
            <pubDate>Sun, 5 Oct 2025 00:00:00 +0000</pubDate>
            <guid isPermaLink="false">blog/2025/0094_tor_browser_install_post.html</guid>
            <description>&amp;lt;div id=&amp;quot;toc&amp;quot; class=&amp;quot;toc&amp;quot;&amp;gt;
&amp;lt;div id=&amp;quot;toctitle&amp;quot;&amp;gt;Table of Contents&amp;lt;/div&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel1&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_導入&amp;quot;&amp;gt;導入&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_tor_とその署名のダウンロード&amp;quot;&amp;gt;Tor とその署名のダウンロード&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_署名の暗号学的検証&amp;quot;&amp;gt;署名の暗号学的検証&amp;lt;/a&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel2&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_1_tor_プロジェクトの公開鍵をインポートする&amp;quot;&amp;gt;1. Tor プロジェクトの公開鍵をインポートする&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_2_署名を確認&amp;quot;&amp;gt;2. 署名を確認&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_実践例有効な署名だが認証されていない鍵&amp;quot;&amp;gt;実践例：有効な署名だが、認証されていない鍵&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_署名を確認する理由は&amp;quot;&amp;gt;署名を確認する理由は？&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_tor_browser_の抽出と起動&amp;quot;&amp;gt;Tor Browser の抽出と起動&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_ubuntu_デスクトップへの統合&amp;quot;&amp;gt;Ubuntu デスクトップへの統合&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_torを使って教育リソースを探索する&amp;quot;&amp;gt;Torを使って教育リソースを探索する&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_tor_browserのアップデート&amp;quot;&amp;gt;Tor Browserのアップデート&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_結論&amp;quot;&amp;gt;結論&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_参照&amp;quot;&amp;gt;参照&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_導入&amp;quot;&amp;gt;導入&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;デジタルプライバシーがますます脅かされる世界では、&amp;lt;strong&amp;gt;Tor Browser&amp;lt;/strong&amp;gt; は匿名性と情報の自由を守るために不可欠なツールのままです。 しかし、ダウンロードしたソフトウェアを、何も持たずに決して実行してはいけない&amp;lt;strong&amp;gt;その真正性を確認した&amp;lt;/strong&amp;gt;. この記事では、次のための包括的な方法を提示します：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;olist arabic&amp;quot;&amp;gt;
&amp;lt;ol class=&amp;quot;arabic&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;Tor Browser&amp;lt;/strong&amp;gt; とその署名をダウンロード`.asc`&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;ダウンロードしたファイルの有効性を確認する&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;Ubuntuで*Tor Browser*をインストールして起動する&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;デスクトップメニューに追加して日常的に使用する&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;Torを介して教育リソースと倫理的OSINTを探索する&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ol&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_tor_とその署名のダウンロード&amp;quot;&amp;gt;Tor とその署名のダウンロード&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;Tor ブラウザ専用のフォルダーを作成してください：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;mkdir -p ~/workspace/tipiak/tor
cd ~/workspace/tipiak/tor&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;次に、Torブラウザのアーカイブとその署名をダウンロードしてください：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;wget https://www.torproject.org/dist/torbrowser/14.5.7/tor-browser-linux-x86_64-14.5.7.tar.xz
wget https://www.torproject.org/dist/torbrowser/14.5.7/tor-browser-linux-x86_64-14.5.7.tar.xz.asc&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_署名の暗号学的検証&amp;quot;&amp;gt;署名の暗号学的検証&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;このステップは&amp;lt;strong&amp;gt;不可欠&amp;lt;/strong&amp;gt;ダウンロードしたファイルが*Tor Project*のものであり、改ざんされていないことを確認するために。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_1_tor_プロジェクトの公開鍵をインポートする&amp;quot;&amp;gt;1. Tor プロジェクトの公開鍵をインポートする&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;gpg --auto-key-locate nodefault,wkd --locate-keys torbrowser@torproject.org&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;キーが正しくインポートされていることを確認してください：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;gpg --list-keys torbrowser@torproject.org&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_2_署名を確認&amp;quot;&amp;gt;2. 署名を確認&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;gpg --verify tor-browser-linux-x86_64-14.5.7.tar.xz.asc tor-browser-linux-x86_64-14.5.7.tar.xz&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;すべてが正しければ、次のメッセージが表示されます：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-none hljs&amp;quot;&amp;gt;gpg: Good signature from &amp;quot;Tor Browser Developers (signing key)&amp;quot;&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;警告が未認証の鍵について表示される場合、これは単にTor Projectの信頼できる鍵にまだ署名していないだけで、署名は依然として有効です。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_実践例有効な署名だが認証されていない鍵&amp;quot;&amp;gt;実践例：有効な署名だが、認証されていない鍵&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;確認時にこのようなメッセージに遭遇することはよくあります：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-none hljs&amp;quot;&amp;gt;gpg --verify tor-browser-linux-x86_64-14.5.7.tar.xz.asc tor-browser-linux-x86_64-14.5.7.tar.xz
gpg: Signature faite le mar. 16 sept. 2025 14:26:26 CEST
gpg:                avec la clef RSA CAAE408AEBE2288E96FC5D5E157432CF78A65729
gpg: Bonne signature de « Tor Browser Developers (signing key) &amp;amp;lt;torbrowser@torproject.org&amp;amp;gt; » [inconnu]
gpg: Attention : cette clef n&amp;#39;est pas certifiée avec une signature de confiance.
gpg:          Rien n&amp;#39;indique que la signature appartient à son propriétaire.
Empreinte de clef principale : EF6E 286D DA85 EA2A 4BA7  DE68 4E2C 6E87 9329 8290
     Empreinte de la sous-clef : CAAE 408A EBE2 288E 96FC  5D5E 1574 32CF 78A6 5729&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;このメッセージは、署名は技術的に「良い」（ファイルは変更されていない）ことを示していますが、GPGシステムは鍵自身への*信頼の証明*を行うことができません。この疑問を払拭するために、メイン鍵のフィンガープリントを比較することが不可欠です。 (&amp;lt;code&amp;gt;EF6E 286D DA85 EA2A 4BA7 DE68 4E2C 6E87 9329 8290&amp;lt;/code&amp;gt;) Tor Projectの公式サイトに掲載されたものと&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;公式サイトによると、期待されるフィンガープリントは：&amp;lt;code&amp;gt;EF6E286DDA85EA2A4BA7DE684E2C6E8793298290&amp;lt;/code&amp;gt;.&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;表示された足跡によって`gpg`公式サイトのものと*正確に*一致すれば、そのキーが正当でありファイルが安全であることを確信できます。「未認証のキー」の警告は、そのときはあなたのGPGローカル設定に関する情報であり、署名の有効性やファイルの真正性については関係ありません。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_署名を確認する理由は&amp;quot;&amp;gt;署名を確認する理由は？&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;GPG署名の検証は、デジタルセキュリティにおける基本的な行為です。 次のことができます:&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;保証する&amp;lt;strong&amp;gt;真正性&amp;lt;/strong&amp;gt;ダウンロードされたソフトウェア&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;悪意ある攻撃者によって侵害されたファイルのインストールを防止する&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;参加する&amp;lt;strong&amp;gt;デジタル主権&amp;lt;/strong&amp;gt;個人的な&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;�責任ある倫理的なデジタル文化を促進する&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
left to right direction
actor &amp;quot;ユーザー&amp;quot; as U
actor &amp;quot;TorProjectサーバー&amp;quot; as S

usecase &amp;quot;Tor とその署名をダウンロード&amp;quot; as D
usecase &amp;quot;公開鍵をインポート&amp;quot; as K
usecase &amp;quot;GPG署名を確認&amp;quot; as V
usecase &amp;quot;Torをインストールして起動&amp;quot; as I

U --&amp;amp;gt; D
U --&amp;amp;gt; K
U --&amp;amp;gt; V
U --&amp;amp;gt; I
S --&amp;amp;gt; D

@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_tor_browser_の抽出と起動&amp;quot;&amp;gt;Tor Browser の抽出と起動&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;ダウンロードしたアーカイブを解凍してください：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;tar -xvf tor-browser-linux-x86_64-14.5.7.tar.xz
cd tor-browser&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;次にブラウザを起動してください：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;./start-tor-browser.desktop&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;最初の起動時に、Torネットワークへの接続を確立するために設定ウィンドウが開きます。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_ubuntu_デスクトップへの統合&amp;quot;&amp;gt;Ubuntu デスクトップへの統合&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;アプリケーションメニューに &amp;lt;strong&amp;gt;Tor Browser&amp;lt;/strong&amp;gt; を追加 :&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;./start-tor-browser.desktop --register-app&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;その後、&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;アプリケーションメニューから*Tor Browser*を起動&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;ドックのお気に入りに追加&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;キーボードショートカットを作成する（希望する場合）&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
start
:Téléchargement de Tor;
:Importation de la clé GPG;
:Vérification de la signature;
if (Signature valide ?) then (Oui)
:Extraction du navigateur;
:Lancement du navigateur Tor;
:Enregistrement dans le bureau;
else (Non)
:Supprimer le fichier compromis;
endif
stop
@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_torを使って教育リソースを探索する&amp;quot;&amp;gt;Torを使って教育リソースを探索する&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;Torは匿名化のためのツールだけではありません。 これは教育および研究資源へのアクセスポータルを構成し、特に次の分野において：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;OSINT (オープンソースインテリジェンス)&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;https://inteltechniques.com&amp;quot;&amp;gt;https://inteltechniques.com&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;https://osintframework.com&amp;quot;&amp;gt;https://osintframework.com&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;教育的な共有とオープンソース&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;https://archive.org&amp;quot;&amp;gt;https://archive.org&amp;lt;/a&amp;gt;(アクセス via Tor でプライバシーを向上)&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;https://github.com/&amp;quot;&amp;gt;https://github.com/&amp;lt;/a&amp;gt;(Torを通じて閲覧可能)&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;https://librarygenesis.pro&amp;quot;&amp;gt;https://librarygenesis.pro&amp;lt;/a&amp;gt;(科学文献への自由アクセス)&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;知識の伝達とデジタル社会における人間の理解&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;デジタル文化、表現の自由、知識へのアクセスに関するリソース&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;サイバーセキュリティと技術の倫理に関するオープンなドキュメンテーション&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_tor_browserのアップデート&amp;quot;&amp;gt;Tor Browserのアップデート&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;最適なセキュリティを確保するために、&amp;lt;strong&amp;gt;Tor Browser&amp;lt;/strong&amp;gt; を最新の状態に保つことが重要です。このブラウザには自動アップデート機能が組み込まれており、コマンドラインからトリガーすることができます。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;Tor Browserのインストールディレクトリから、スタートスクリプトを再起動するだけです：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;cd ~/workspace/tipiak/tor/tor-browser
./start-tor-browser.desktop&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;起動時に、&amp;lt;strong&amp;gt;Tor Browser&amp;lt;/strong&amp;gt; は自動的に新しいバージョンが存在するかを確認します。存在する場合は、それをダウンロードしてインストールします。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;このシンプルな方法は、常に最新のセキュリティパッチと最新の改善が適用されていることを保証します。これは、安全なブラウジングに不可欠です。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_結論&amp;quot;&amp;gt;結論&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;ダウンロードを確認することは、安全なデジタル環境で成長したいすべての人にとって必須の習慣です。 Torを検証済みの方法でインストールすることは&amp;lt;strong&amp;gt;デジタルの整合性を守る&amp;lt;/strong&amp;gt;, &amp;lt;strong&amp;gt;フリーソフトウェアへの信頼を保つ&amp;lt;/strong&amp;gt;, et &amp;lt;strong&amp;gt;情報自立性を強化する&amp;lt;/strong&amp;gt;。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;デジタルセキュリティは、 妄想ではなく、 良心に基づく行為である。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
title Torの使用の概要
actor Utilisateur
rectangle &amp;quot;Tor ブラウザ&amp;quot; {
rectangle &amp;quot;匿名&amp;quot; as A
rectangle &amp;quot;OSINT調査&amp;quot; as O
rectangle &amp;quot;教育的な共有&amp;quot; as E
}
Utilisateur --&amp;amp;gt; A
Utilisateur --&amp;amp;gt; O
Utilisateur --&amp;amp;gt; E
@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_参照&amp;quot;&amp;gt;参照&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;Tor Projectの公式サイト:https://www.torproject.org/download/[&amp;lt;a href=&amp;quot;https://www.torproject.org/download/&amp;quot; class=&amp;quot;bare&amp;quot;&amp;gt;https://www.torproject.org/download/&amp;lt;/a&amp;gt;]&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;署名検証ドキュメント：https://support.torproject.org/tbb/how-to-verify-signature/[&amp;lt;a href=&amp;quot;https://support.torproject.org/tbb/how-to-verify-signature/&amp;quot; class=&amp;quot;bare&amp;quot;&amp;gt;https://support.torproject.org/tbb/how-to-verify-signature/&amp;lt;/a&amp;gt;]&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;Ubuntuドキュメント：https://ubuntu.com[&amp;lt;a href=&amp;quot;https://ubuntu.com&amp;quot; class=&amp;quot;bare&amp;quot;&amp;gt;https://ubuntu.com&amp;lt;/a&amp;gt;]&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;教育的アーカイブ :https://archive.org/details/opensource[&amp;lt;a href=&amp;quot;https://archive.org/details/opensource&amp;quot; class=&amp;quot;bare&amp;quot;&amp;gt;https://archive.org/details/opensource&amp;lt;/a&amp;gt;]&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;admonitionblock note&amp;quot;&amp;gt;
&amp;lt;table&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;icon&amp;quot;&amp;gt;
&amp;lt;i class=&amp;quot;fa icon-note&amp;quot; title=&amp;quot;Note&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;
&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;この記事は、*セキュリティとデジタル意識*シリーズの一部です。 責任のある教育的な実践を促進することを目的とする フリーのツールを中心に&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/table&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;</description>
        </item><item>
            <title>第5条：共有された libs.versions.toml の冒険</title>
            <link >https://cheroliv.com/blog/2025/0093_gradle_plugin_toml_composite_build_post.html</link>
            <pubDate>Sat, 27 Sep 2025 00:00:00 +0000</pubDate>
            <guid isPermaLink="false">blog/2025/0093_gradle_plugin_toml_composite_build_post.html</guid>
            <description>&amp;lt;div id=&amp;quot;toc&amp;quot; class=&amp;quot;toc&amp;quot;&amp;gt;
&amp;lt;div id=&amp;quot;toctitle&amp;quot;&amp;gt;Sommaire&amp;lt;/div&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel1&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_はじめに&amp;quot;&amp;gt;はじめに&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_1_バージョンカタログ_libs_versions_toml_リマインダー&amp;quot;&amp;gt;1. バージョンカタログ (&amp;lt;code&amp;gt;libs.versions.toml&amp;lt;/code&amp;gt;) : リマインダー&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_2_問題複合ビルドと二つの別々な世界&amp;quot;&amp;gt;2. 問題：複合ビルドと二つの別々な世界&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_3_解決策依存関係の解決の共有&amp;quot;&amp;gt;3. 解決策:依存関係の解決の共有&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_4_結論適切に管理されたコンポジットビルドの力&amp;quot;&amp;gt;4. 結論：適切に管理されたコンポジットビルドの力&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_はじめに&amp;quot;&amp;gt;はじめに&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;対象ユーザー：マルチビルドプロジェクトでの依存関係管理に直面しているGradle開発者&amp;lt;/div&amp;gt;
&amp;lt;p&amp;gt;プラグインを作るための私たちの探求の中で`site-baker`私たちはクリーンで集中されたコードベースを維持しようと努めてきました。現代のGradleエコシステムにおけるベストプラクティスの一つは、の使用です&amp;lt;strong&amp;gt;バージョンカタログ&amp;lt;/strong&amp;gt; (&amp;lt;code&amp;gt;libs.versions.toml&amp;lt;/code&amp;gt;) で依存関係を管理するために。 しかし、プロジェクトがより複雑になるとどうなるでしょうか、例えば&amp;lt;strong&amp;gt;複合をビルド&amp;lt;/strong&amp;gt;ここで、独立したビルド（私たちのプラグイン）は他のものに含めなければなりませんか？&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;そこが私たちの冒険が思いがけない転機を迎えた場所だった。私たちは私たちのプラグインが`site-baker`, それ自体が Gradle プロジェクトである、私たちのメインプロジェクトと同じバージョン カタログを使用します。 この記事は、私たちのシリーズの第五回目で、その課題をどのように解決したかを説明しています。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_1_バージョンカタログ_libs_versions_toml_リマインダー&amp;quot;&amp;gt;1. バージョンカタログ (&amp;lt;code&amp;gt;libs.versions.toml&amp;lt;/code&amp;gt;) : リマインダー&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;ファイル`gradle/libs.versions.toml`Gradleの機能で、プロジェクトの依存関係のバージョンと座標を一元管理することができます。通常、4つのセクションに構成されています：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;code&amp;gt;[versions]&amp;lt;/code&amp;gt;: バージョン番号のエイリアスを定義します (例:`kotlin = &amp;quot;1.9.20&amp;quot;`).&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;code&amp;gt;[libraries]&amp;lt;/code&amp;gt;: 完全な依存関係のエイリアスを設定します。上で定義したバージョンを使用します（例:`kotlin-stdlib = { module = &amp;quot;org.jetbrains.kotlin:kotlin-stdlib&amp;quot;, version.ref = &amp;quot;kotlin&amp;quot; }`)&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;code&amp;gt;[bundles]`複数のライブラリを単一のエイリアスにグループ化（例：`jackson = [&amp;quot;jackson-core&amp;quot;, &amp;quot;jackson-databind&amp;quot;]&amp;lt;/code&amp;gt;).&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;`[plugins]`Gradle プラグインのエイリアスを定義します。&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;定義すると、Gradle は自動的に型付きアクセッサを生成し、これによりあなたの`build.gradle.kts`ずっと読みやすい :&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-kotlin hljs&amp;quot; data-lang=&amp;quot;kotlin&amp;quot;&amp;gt;dependencies {
    // Au lieu de : implementation(&amp;quot;org.jetbrains.kotlin:kotlin-stdlib:1.9.20&amp;quot;)
    implementation(libs.kotlin.stdlib)
}&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;バージョン カタログのデータフロー&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
!theme plain
file &amp;quot;gradle/libs.versions.toml&amp;quot; as Toml
node &amp;quot;Gradle&amp;quot; as G
file &amp;quot;build.gradle.kts&amp;quot; as BuildScript

Toml --&amp;amp;gt; G : &amp;quot;によって読まれている&amp;quot;
G --&amp;amp;gt; BuildScript : &amp;quot;アクセッサを生成 `libs&amp;quot;
BuildScript -&amp;amp;gt; G : &amp;quot;libs` を使用して 依存関係を宣言する&amp;quot;
@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_2_問題複合ビルドと二つの別々な世界&amp;quot;&amp;gt;2. 問題：複合ビルドと二つの別々な世界&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;私たちのプロジェクト構造は&amp;lt;strong&amp;gt;ビルド コンポジット&amp;lt;/strong&amp;gt;. 主要なプロジェクト (&amp;lt;code&amp;gt;thymeleaf.cheroliv.com&amp;lt;/code&amp;gt;) プラグインのプロジェクトを含む (&amp;lt;code&amp;gt;site-baker&amp;lt;/code&amp;gt;) コマンド経由で`includeBuild(&amp;quot;site-baker&amp;quot;)&amp;lt;code&amp;gt;ファイルの中に`settings.gradle.kts&amp;lt;/code&amp;gt;。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;コンポジットビルドの構造&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
!theme plain
package &amp;quot;主要プロジェクト&amp;quot; {
  file &amp;quot;settings.gradle.kts&amp;quot; as MainSettings
  folder &amp;quot;グレードル&amp;quot; {
    file &amp;quot;libs.versions.toml&amp;quot; as MainToml
  }
}

package &amp;quot;プラグイン `site-baker` (Build Inclus)&amp;quot; {
  file &amp;quot;settings.gradle.kts&amp;quot; as PluginSettings
  file &amp;quot;build.gradle.kts&amp;quot; as PluginBuild
}

MainSettings -&amp;amp;gt; PluginSettings : `includeBuild(&amp;quot;サイトベーカー&amp;quot;)`
PluginBuild ..&amp;amp;gt; MainToml : **Voulait accéder à...**
note right on link: ...mais ne pouvait pas !
@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;問題は、デフォルトでは、インクルードされたビルドは&amp;lt;strong&amp;gt;別世界&amp;lt;/strong&amp;gt;. 自分固有の設定があり、自分固有のライフサイクルがあり、ファイルを見ません。&amp;lt;code&amp;gt;libs.versions.toml`メインビルドの。 私たちの`plugin/build.gradle.kts`使おうと試みていた`libs.plugins.kotlin.jvm&amp;lt;/code&amp;gt;, しかしオブジェクト`libs` n&amp;amp;#8217;était pas généré à partir du bon fichier TOML, provoquant des erreurs de build.&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_3_解決策依存関係の解決の共有&amp;quot;&amp;gt;3. 解決策:依存関係の解決の共有&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;何度か調べた結果、解決策はこのケースのために正確に設計されたGradleの機能であることがわかりました：&amp;lt;code&amp;gt;dependencyResolutionManagement&amp;lt;/code&amp;gt;.&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;ファイル内`settings.gradle.kts` du &amp;lt;strong&amp;gt;包括的な構築&amp;lt;/strong&amp;gt;(&amp;lt;code&amp;gt;site-baker/settings.gradle.kts&amp;lt;/code&amp;gt;), Gradleに使用するバージョンカタログの場所を伝えることができます。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;ここに、私たちが追加した設定に`site-baker/settings.gradle.kts`:&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-kotlin hljs&amp;quot; data-lang=&amp;quot;kotlin&amp;quot;&amp;gt;// site-baker/settings.gradle.kts

dependencyResolutionManagement {
    repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
    repositories {
        gradlePluginPortal()
        mavenCentral()
    }
    versionCatalogs {
        create(&amp;quot;libs&amp;quot;) {
            from(files(&amp;quot;../gradle/libs.versions.toml&amp;quot;))
        }
    }
}

rootProject.name = &amp;quot;site-baker&amp;quot;
include(&amp;quot;plugin&amp;quot;)&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;重要な部分を分析しましょう：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-kotlin hljs&amp;quot; data-lang=&amp;quot;kotlin&amp;quot;&amp;gt;versionCatalogs {
    create(&amp;quot;libs&amp;quot;) { // Crée un catalogue nommé &amp;#39;libs&amp;#39;
        from(files(&amp;quot;../gradle/libs.versions.toml&amp;quot;)) // En utilisant ce fichier
    }
}&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;code&amp;gt;create(&amp;quot;libs&amp;quot;)&amp;lt;/code&amp;gt;: 私たちは、エイリアスを通じてアクセスできるバージョンのカタログを宣言します。&amp;lt;code&amp;gt;libs&amp;lt;/code&amp;gt;.&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;code&amp;gt;from(files(&amp;quot;../gradle/libs.versions.toml&amp;quot;))&amp;lt;/code&amp;gt;: これが魔法です。 私たちはGradleに、このカタログのソースがこのディレクトリ内にあるTOMLファイルであることを伝えます。&amp;lt;code&amp;gt;gradle&amp;lt;/code&amp;gt; du &amp;lt;strong&amp;gt;親プロジェクト&amp;lt;/strong&amp;gt;(&amp;lt;code&amp;gt;../&amp;lt;/code&amp;gt;“).”&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;この設定では、ビルド`site-baker`彼は今、メインプロジェクトのバージョンカタログを使用しなければならないことを知っている。オブジェクト`libs`正しく生成され、依存関係は予定通りに解決されます。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_4_結論適切に管理されたコンポジットビルドの力&amp;quot;&amp;gt;4. 結論：適切に管理されたコンポジットビルドの力&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;この経験は多くの教訓を得るものでした。バージョンカタログは保守性に優れた素晴らしいツールですが、複合ビルドシナリオでのその動作は必ずしも直感的ではありません。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;ポイントは、インクルードされたビルドでも独立したビルドのままであることを覚えておくことです。バージョンカタログのような設定を共有するには、Gradleが提供する明示的なメカニズム、例えばブロックを使用する必要があります。&amp;lt;code&amp;gt;dependencyResolutionManagement`中`settings.gradle.kts&amp;lt;/code&amp;gt;.&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;この問題を解決することで、私たちのビルドをきれいにするだけでなく、プラグインとメインプロジェクトが依存関係について唯一の真実のソースを共有することを確認することで、プロジェクトの一貫性も強化しました。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;次の記事では、依存関係の管理が堅牢かつ集中化された今、さらに複雑なタスクを追加することでプラグインを充実させていきます。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;</description>
        </item><item>
            <title>第4条：Gradle構成キャッシュの罠</title>
            <link >https://cheroliv.com/blog/2025/0092_gradle_configuration_cache_post.html</link>
            <pubDate>Fri, 26 Sep 2025 00:00:00 +0000</pubDate>
            <guid isPermaLink="false">blog/2025/0092_gradle_configuration_cache_post.html</guid>
            <description>&amp;lt;div id=&amp;quot;toc&amp;quot; class=&amp;quot;toc&amp;quot;&amp;gt;
&amp;lt;div id=&amp;quot;toctitle&amp;quot;&amp;gt;Sommaire&amp;lt;/div&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel1&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_導入&amp;quot;&amp;gt;導入&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_症状幽霊ビルド&amp;quot;&amp;gt;症状：幽霊ビルド&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_調査構成キャッシュとは何ですか&amp;quot;&amp;gt;調査：構成キャッシュとは何ですか？&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_問題の原因_適合していないプラグイン&amp;quot;&amp;gt;問題の原因: 適合していないプラグイン&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_一時的なソリューションキャッシュを無効にする&amp;quot;&amp;gt;一時的なソリューション：キャッシュを無効にする&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_真の解決策プラグインを互換性を持たせる&amp;quot;&amp;gt;真の解決策：プラグインを互換性を持たせる&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_導入&amp;quot;&amp;gt;導入&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;対象 : すでに &amp;quot;magiques&amp;quot; または予期しないビルドの挙動に遭遇した Gradle 開発者&amp;lt;/div&amp;gt;
&amp;lt;p&amp;gt;私たちのプラグイン作成の冒険で`site-baker`, 我々は TDD を厳格に実践しました。各機能はテストされ、検証され、そして我々は確信を持って進んでいきました。そしてある日、予期せぬことが起こりました。ビルドは予測不能な動作を始めました。プラグインのロジックや設定ファイルの変更が無視されているかのように見え、かつて信頼できた機能テストも理由もなく失敗し始めました。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;この種の問題は信じがたいほどイライラさせることがあります。これはツールの信頼性と私たちのコードの妥当性を疑問視します。激しいデバッグセッションの後、犯人が特定されました：その&amp;lt;strong&amp;gt;Gradleの設定キャッシュ&amp;lt;/strong&amp;gt;。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_症状幽霊ビルド&amp;quot;&amp;gt;症状：幽霊ビルド&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;問題は様々な形で現れていた：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;olist arabic&amp;quot;&amp;gt;
&amp;lt;ol class=&amp;quot;arabic&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;タスク内の文字列を編集していた`println`, しかし古い文字列は実行時に表示され続けた。&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;ファイルの中で値を変更していた。`managed-jbake-context.yml`しかし、プラグインはファイルが変更されていないかのように振る舞った。&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;機能テストは、その場でテストプロジェクトを作成するものですが、プラグインが新しく作成された設定ファイルを検出しているようには見えず、失敗していました。&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ol&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;まるで Gradle が私たちのビルドの「幽霊バージョン」を実行しているかのように、すべてが進行していました。最新の変更を無視して。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_調査構成キャッシュとは何ですか&amp;quot;&amp;gt;調査：構成キャッシュとは何ですか？&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;構成キャッシュは、比較的新しい機能であり、Gradleの非常に強力な機能です。新しいバージョンではデフォルトで有効になっています。その目的は、ビルドをより速くすることです。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;olist arabic&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;原理は単純です：&amp;lt;/div&amp;gt;
&amp;lt;ol class=&amp;quot;arabic&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;最初の実行時に、Gradle は フェーズ を実行します&amp;lt;strong&amp;gt;設定&amp;lt;/strong&amp;gt;(の読み取り`build.gradle.kts`, タスクの作成, 依存関係の解決) と タスクグラフを構築します。&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;このフェーズの終わりに、Gradle&amp;lt;strong&amp;gt;このタスクグラフをシリアライズして&amp;lt;/strong&amp;gt;そしてそれをキャッシュに保存します。&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;次の実行時に何も変更されていない場合（ビルドスクリプトが,&amp;lt;code&amp;gt;gradle.properties&amp;lt;/code&amp;gt;, など), Gradle&amp;lt;strong&amp;gt;設定フェーズを完全にスキップする&amp;lt;/strong&amp;gt;そしてキャッシュされたタスクグラフを再利用します。&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ol&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;大規模なプロジェクトでは時間の節約が驚くほど顕著です。ただし、このパフォーマンスにはコストが伴います：プラグインの記述方法に厳格なルールを課します。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;構成キャッシュのライフサイクル&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
start
:Première exécution;
:Phase de Configuration;
:Création du graphe de tâches;
:Mise en cache du graphe;
:Phase d&amp;#39;Exécution;
end

start
:Exécution suivante;
if (Cache valide ?) then (oui)
  :Restauration du graphe depuis le cache;
  note right
    La phase de configuration
    est sautée !
  end note
else (non)
  :Phase de Configuration;
  :Mise à jour du cache;
endif
:Phase d&amp;#39;Exécution;
stop
@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_問題の原因_適合していないプラグイン&amp;quot;&amp;gt;問題の原因: 適合していないプラグイン&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;私たちのプラグイン`site-baker`無意識のうちに、設定キャッシュのいくつかのルールを違反していた。タスクグラフがシリアライズ可能であるためには、タスクはオブジェクトなどの複雑なオブジェクトへの参照を含んではならない。`Project`または、実行フェーズ中に任意のファイルを読み込むことができます。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;私たちの主な間違いは、タスクの実行ロジック内でYAMLファイルの内容を直接読み込んでいたことです。これは、拡張機能に保存されているパスへの参照を使用して行われました。このアプローチは、この読み込みがモデル化されていないような場合、Gradleがファイルの内容が変更されたかどうかを知ることができないため、キャッシュと互換性がありません。&amp;lt;strong&amp;gt;タスクエントリ&amp;lt;/strong&amp;gt; (Task Input).&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_一時的なソリューションキャッシュを無効にする&amp;quot;&amp;gt;一時的なソリューション：キャッシュを無効にする&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;私たちのブロックを解除し、予測可能なビルド動作を取り戻すために、最も速い方法は設定キャッシュを無効にすることでした。ファイルに以下の行を追加するだけです`gradle.properties`プラグインを使用しているプロジェクト（または私たちの場合、テストプロジェクト）の`site-baker`).&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-properties hljs&amp;quot; data-lang=&amp;quot;properties&amp;quot;&amp;gt;# site-baker/gradle.properties
org.gradle.configuration-cache=false&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;瞬時に、ビルドは通常の動作を取り戻しました。各実行が構成フェーズを再起動し、私たちの変更が考慮されました。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;ただし、これは回避策であり、持続可能な解決策ではありません。パフォーマンスを犠牲にし、プラグインの根本的な問題を解決しません。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_真の解決策プラグインを互換性を持たせる&amp;quot;&amp;gt;真の解決策：プラグインを互換性を持たせる&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;プラグインが現代のGradleエコシステムの良い市民であるためには、設定キャッシュと互換性がある必要があります。これは、データがタスクに流れる方法を見直すことを意味します。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;キーはそれらを使うことです&amp;lt;strong&amp;gt;プロバイダーのAPI&amp;lt;/strong&amp;gt;Gradleの。 直接の値を渡す代わりに（例えば`String` ou un &amp;lt;code&amp;gt;File&amp;lt;/code&amp;gt;) 私たちのタスクに対して、私たちは何かを通過しなければならない`Property&amp;amp;lt;T&amp;amp;gt;`または`Provider&amp;amp;lt;T&amp;amp;gt;`.&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;olist arabic&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;以下はリファクタリング計画です：&amp;lt;/div&amp;gt;
&amp;lt;ol class=&amp;quot;arabic&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;タスクエントリを宣言する :&amp;lt;/strong&amp;gt;YAMLファイルをパースするタスクは、このファイルを入力として宣言しなければなりません。そのためにアノテーションを使用します。&amp;lt;code&amp;gt;@InputFile&amp;lt;/code&amp;gt;。&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ol&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;[source,kotlin] python&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;</description>
        </item><item>
            <title>第3項：GradleプラグインにおけるTDDを用いたYAMLパースのためのJacksonの統合</title>
            <link >https://cheroliv.com/blog/2025/0091_jackson_yaml_tdd_post.html</link>
            <pubDate>Thu, 25 Sep 2025 00:00:00 +0000</pubDate>
            <guid isPermaLink="false">blog/2025/0091_jackson_yaml_tdd_post.html</guid>
            <description>&amp;lt;div id=&amp;quot;toc&amp;quot; class=&amp;quot;toc&amp;quot;&amp;gt;
&amp;lt;div id=&amp;quot;toctitle&amp;quot;&amp;gt;Sommaire&amp;lt;/div&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel1&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_導入&amp;quot;&amp;gt;導入&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_1_コンテキスト_私たちのプラグイン_site_baker&amp;quot;&amp;gt;1. コンテキスト: 私たちのプラグイン `site-baker&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_2_kotlin_での設定のモデリング&amp;quot;&amp;gt;2. Kotlin での設定のモデリング&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_3_jacksonのbuild_gradle_ktsへの統合&amp;quot;&amp;gt;3. Jacksonの`build.gradle.kts`への統合&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_4_tddアプローチyamlパースのテスト&amp;quot;&amp;gt;4. TDDアプローチ：YAMLパースのテスト&amp;lt;/a&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel2&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_4_1_単体テスト_yamlをkotlinオブジェクトにマッピング&amp;quot;&amp;gt;4.1. 単体テスト: YAMLをKotlinオブジェクトにマッピング&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_4_2_機能テスト構成ファイルの読み取りを検証する&amp;quot;&amp;gt;4.2. 機能テスト：構成ファイルの読み取りを検証する&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_5_パースフローの可視化&amp;quot;&amp;gt;5. パースフローの可視化&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_結論&amp;quot;&amp;gt;結論&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_導入&amp;quot;&amp;gt;導入&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;対象 : 中級 Gradle 開発者で、複雑な設定を管理したい人&amp;lt;/div&amp;gt;
&amp;lt;p&amp;gt;Gradleプラグインの開発において、複雑な構成の管理は一般的な作業です。DSLに数百のプロパティを詰め込むのではなく、外部ファイル、例えばYAMLに設定を定義するほうが、すっきりしており保守しやすいことが多いです。この記事では、強力なJacksonライブラリを使ってYAMLファイルをKotlinオブジェクトにパースする統合方法を、厳格なTDDアプローチを採用してプラグインの堅牢性を確保する形でガイドします。&amp;lt;code&amp;gt;site-baker&amp;lt;/code&amp;gt;。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_1_コンテキスト_私たちのプラグイン_site_baker&amp;quot;&amp;gt;1. コンテキスト: 私たちのプラグイン `site-baker&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;私たちのプラグイン`site-baker`は、静的サイトの生成とデプロイを自動化するように設計されています。YAML設定ファイルを読み込む必要があります (&amp;lt;code&amp;gt;managed-jbake-context.yml&amp;lt;/code&amp;gt;) ソースのパス、デプロイ先、Gitの識別子などの情報を取得するために。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;パースしたいYAML設定はこのようになります：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-yaml hljs&amp;quot; data-lang=&amp;quot;yaml&amp;quot;&amp;gt;bake:
  srcPath: &amp;quot;./site/jbake&amp;quot;
  destDirPath: &amp;quot;bake&amp;quot;
  cname: &amp;quot;cheroliv.com&amp;quot;
pushPage:
  from: &amp;quot;bake&amp;quot;
  to: &amp;quot;cvs&amp;quot;
  repo:
    name: &amp;quot;trainings&amp;quot;
    repository: &amp;quot;https://github.com/pages-content/pages-content.github.io.git&amp;quot;
    credentials:
      username: &amp;quot;USERNAME&amp;quot;
      password: &amp;quot;SECRET_TOKEN&amp;quot;
  branch: &amp;quot;main&amp;quot;
  message: &amp;quot;cheroliv.com&amp;quot;
# ... autres configurations (pushMaquette, supabase, etc.)&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_2_kotlin_での設定のモデリング&amp;quot;&amp;gt;2. Kotlin での設定のモデリング&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;パースする前に、Kotlinでデータの構造を定義する必要があります。Jacksonはこれらのクラスを使用してYAMLコンテンツを自動的にマッピングします。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-kotlin hljs&amp;quot; data-lang=&amp;quot;kotlin&amp;quot;&amp;gt;// plugin/src/main/kotlin/com/cheroliv/site/baker/data/SiteConfiguration.kt
package com.cheroliv.site.baker.data

import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory
import com.fasterxml.jackson.module.kotlin.readValue
import com.fasterxml.jackson.module.kotlin.registerKotlinModule

fun parseSiteConfiguration(yaml: String): SiteConfiguration {
    val mapper = ObjectMapper(YAMLFactory()).registerKotlinModule()
    return mapper.readValue(yaml)
}

data class GitPushConfiguration(
    val from: String = &amp;quot;&amp;quot;,
    val to: String = &amp;quot;&amp;quot;,
    val repo: RepositoryConfiguration = RepositoryConfiguration(),
    val branch: String = &amp;quot;&amp;quot;,
    val message: String = &amp;quot;&amp;quot;,
)

data class RepositoryConfiguration(
    val name: String = &amp;quot;&amp;quot;,
    val repository: String = &amp;quot;&amp;quot;,
    val credentials: RepositoryCredentials = RepositoryCredentials(),
) {
    companion object {
        const val ORIGIN = &amp;quot;origin&amp;quot;
        const val CNAME = &amp;quot;CNAME&amp;quot;
        const val REMOTE = &amp;quot;remote&amp;quot;
    }
}

data class RepositoryCredentials(val username: String = &amp;quot;&amp;quot;, val password: String = &amp;quot;&amp;quot;)

data class SiteConfiguration(
    val bake: BakeConfiguration = BakeConfiguration(),
    val pushPage: GitPushConfiguration = GitPushConfiguration(),
    val pushMaquette: GitPushConfiguration = GitPushConfiguration(),
    val pushSource: GitPushConfiguration? = null,
    val pushTemplate: GitPushConfiguration? = null,
    val supabase: SupabaseContactFormConfig? = null
)

data class BakeConfiguration(
    val srcPath: String = &amp;quot;&amp;quot;,
    val destDirPath: String = &amp;quot;&amp;quot;,
    val cname: String? = null,
)

// ... (autres data classes pour Supabase, si nécessaire)&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;機能`parseSiteConfiguration`これはデシリアライズのエントリーポイントです。使用します`ObjectMapper`Jacksonの、設定済みの`YAMLFactory`YAMLフォーマットに対して`registerKotlinModule()`Kotlinの特殊機能のサポート（例えばプロパティのデフォルト値など）のため。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_3_jacksonのbuild_gradle_ktsへの統合&amp;quot;&amp;gt;3. Jacksonの`build.gradle.kts`への統合&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;Jacksonを使用するには、必要な依存関係を追加する必要がありますの`build.gradle.kts`私たちのモジュールの`plugin`:&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-kotlin hljs&amp;quot; data-lang=&amp;quot;kotlin&amp;quot;&amp;gt;// plugin/build.gradle.kts
dependencies {
    // Jackson for YAML parsing
    implementation(&amp;quot;com.fasterxml.jackson.module:jackson-module-kotlin:2.18.3&amp;quot;)
    implementation(&amp;quot;com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:2.18.3&amp;quot;)

    // ... autres dépendances
}&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;私たちは使用します`jackson-module-kotlin`Kotlinのサポートのためにおよび`jackson-dataformat-yaml`YAML形式の管理のために。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_4_tddアプローチyamlパースのテスト&amp;quot;&amp;gt;4. TDDアプローチ：YAMLパースのテスト&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;今、TDDを適用してパースロジックを検証しましょう。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_4_1_単体テスト_yamlをkotlinオブジェクトにマッピング&amp;quot;&amp;gt;4.1. 単体テスト: YAMLをKotlinオブジェクトにマッピング&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;私たちは単体テストで始めます`SiteBakerPluginTest.kt`関数が機能しているかを確認するために`parseSiteConfiguration`YAML文字列をオブジェクトに正しく変換できます`SiteConfiguration`.&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-kotlin hljs&amp;quot; data-lang=&amp;quot;kotlin&amp;quot;&amp;gt;// plugin/src/test/kotlin/com/cheroliv/site/baker/SiteBakerPluginTest.kt
@Test
fun `can map configuration text to SiteConfiguration object`() {
    val yamlString = &amp;quot;../../managed-jbake-context.yml&amp;quot;
        .run(::File)
        .readText()
        .trimIndent()

    val config: SiteConfiguration = parseSiteConfiguration(yamlString)

    assertEquals(&amp;quot;cheroliv.com&amp;quot;, config.bake.cname)
    assertEquals(&amp;quot;main&amp;quot;, config.pushPage.branch)
    assertEquals(&amp;quot;https://github.com/pages-content/pages-content.github.io.git&amp;quot;, config.pushPage.repo.repository)
}&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;このテストはファイルの内容を読み込みます`managed-jbake-context.yml`(テストが有効であるために存在しなければならない)およびオブジェクトに対するアサーションを実行する`SiteConfiguration`結果として。 YAML のキーの値が正しくマッピングされていることを検証します。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_4_2_機能テスト構成ファイルの読み取りを検証する&amp;quot;&amp;gt;4.2. 機能テスト：構成ファイルの読み取りを検証する&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;プラグインがそのDSLを通じて設定ファイルを読み取ることができ、実際のGradle環境でパースが機能することを確認するために、私たちは機能テストを追加します`SiteBakerPluginFunctionalTest.kt`。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;このテストは重要です。なぜなら、実際のプロジェクトでのプラグインの実行をシミュレートするからです。これが必要です&amp;lt;strong&amp;gt;密閉&amp;lt;/strong&amp;gt;, すなわち彼は自分でファイルを作成しなければならない`managed-jbake-context.yml`制御されたコンテンツを使用して、テストの再現性と隔離を保証します。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-kotlin hljs&amp;quot; data-lang=&amp;quot;kotlin&amp;quot;&amp;gt;// plugin/src/functionalTest/kotlin/com/cheroliv/site/baker/SiteBakerPluginFunctionalTest.kt
@Test
fun `config file contains good data`(){
    val configContent = configFile.readText(UTF_8)
    // Vérifications comme dans vos commentaires
    assertTrue(configContent.contains(&amp;quot;bake&amp;quot;))
    assertTrue(configContent.contains(&amp;quot;pushPage&amp;quot;))
    assertTrue(configContent.contains(&amp;quot;repository&amp;quot;))
}&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;この機能テストは、テストの一時ディレクトリにコピーされた設定ファイルに期待されるデータが含まれていることを確認します。このテストは直接 YAML を Kotlin オブジェクトにパースしませんが、ファイルとその内容の存在を検証し、これはプラグインによるパースに必要な前提条件となります。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_5_パースフローの可視化&amp;quot;&amp;gt;5. パースフローの可視化&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;次の図は、YAML 設定のパース時のデータフローとインタラクションを示しています：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
actor &amp;quot;Gradle ユーザー&amp;quot; as User
participant &amp;quot;build.gradle.kts&amp;quot; as BuildScript
participant &amp;quot;SiteBakerPlugin&amp;quot; as Plugin
participant &amp;quot;サイトエクステンション&amp;quot; as Extension
participant &amp;quot;managed-jbake-context.yml&amp;quot; as ConfigFile
participant &amp;quot;parseSiteConfiguration()&amp;quot; as Parser
participant &amp;quot;SiteConfiguration ( Kotlin オブジェクト )&amp;quot; as KotlinObject

User -&amp;amp;gt; BuildScript : Applique le plugin et configure le DSL
BuildScript -&amp;amp;gt; Plugin : apply()
Plugin -&amp;amp;gt; Extension : Crée et enregistre l&amp;#39;extension &amp;#39;site&amp;#39;
User -&amp;amp;gt; BuildScript : site { configPath = &amp;quot;...&amp;quot; }
BuildScript -&amp;amp;gt; Extension : Définit configPath

Plugin -&amp;amp;gt; ConfigFile : Lit le fichier (via configPath)
ConfigFile --&amp;amp;gt; Plugin : Contenu YAML
Plugin -&amp;amp;gt; Parser : Appelle parseSiteConfiguration(yamlString)
Parser -&amp;amp;gt; KotlinObject : Mappe le YAML en objet SiteConfiguration
KotlinObject --&amp;amp;gt; Plugin : Retourne l&amp;#39;objet configuré

@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_結論&amp;quot;&amp;gt;結論&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;TDDのアプローチを取ることで、Jacksonライブラリを使用してYAML設定ファイルをKotlinオブジェクトにパースし、Gradleプラグインに正常に組み込むことができました。この方法により、以下のことが可能になりました：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;明確にモデリング&amp;lt;/strong&amp;gt;私たちの構成とKotlinのデータクラス。&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;パースロジックを検証する&amp;lt;/strong&amp;gt;対象となる単体テストで。&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;統合の確保&amp;lt;/strong&amp;gt;実際の Gradle 環境で、密閉された機能テストにより。&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;この堅固な基盤により、この設定に基づく機能でプラグインを拡張する大きな自信を得られ、コードの保守性と堅牢性も確保できます。YAMLのパースは今ではプラグインの信頼性が高くテスト済みの機能となっています。&amp;lt;code&amp;gt;site-baker&amp;lt;/code&amp;gt;。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;</description>
        </item><item>
            <title>記事 2 : TDDアプローチを使用してGradleプラグインを開発する</title>
            <link >https://cheroliv.com/blog/2025/0090_TDD_gradle_plugin_post.html</link>
            <pubDate>Wed, 24 Sep 2025 00:00:00 +0000</pubDate>
            <guid isPermaLink="false">blog/2025/0090_TDD_gradle_plugin_post.html</guid>
            <description>&amp;lt;div id=&amp;quot;toc&amp;quot; class=&amp;quot;toc&amp;quot;&amp;gt;
&amp;lt;div id=&amp;quot;toctitle&amp;quot;&amp;gt;Table of Contents&amp;lt;/div&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel1&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_プロジェクトの初期化&amp;quot;&amp;gt;プロジェクトの初期化&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_2_私たちの最初のtddサイクル_タスクを記録する&amp;quot;&amp;gt;2. 私たちの最初のTDDサイクル : タスクを記録する&amp;lt;/a&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel2&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_2_1_まずテストする_失敗するテスト&amp;quot;&amp;gt;2.1. まずテストする (失敗するテスト)&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_2_2_コードの次に_テストを通す&amp;quot;&amp;gt;2.2. コードの次に (テストを通す)&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_3_第2サイクル_tdd_dsl拡張を追加&amp;quot;&amp;gt;3. 第2サイクル TDD : DSL拡張を追加&amp;lt;/a&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel2&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_3_1_最初のテスト&amp;quot;&amp;gt;3.1. 最初のテスト&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_3_2_コードその後&amp;quot;&amp;gt;3.2. コードその後&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_4_機能テスト統合の検証&amp;quot;&amp;gt;4. 機能テスト：統合の検証&amp;lt;/a&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel2&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_4_1_統合テスト_制御された環境を作成する&amp;quot;&amp;gt;4.1. 統合テスト : 制御された環境を作成する&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_4_2_ロジックを最終化する&amp;quot;&amp;gt;4.2. ロジックを最終化する&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_結論&amp;quot;&amp;gt;結論&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div id=&amp;quot;preamble&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;この記事では、(TDD - テスト駆動開発) アプローチを使用して、Gradleプラグインのための堅牢な開発基盤を構築する方法について探ります。 この方法により、私たちのコードが堅牢で保守しやすく、最初から正確に要件を満たすことが保証されます。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_プロジェクトの初期化&amp;quot;&amp;gt;プロジェクトの初期化&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;Gradleはコマンドを使うことで新しいプラグインの作成を大いに容易にします。&amp;lt;code&amp;gt;gradle init&amp;lt;/code&amp;gt;. &amp;quot;Gradle Plugin&amp;quot;をKotlinで作成することを選択すると、すぐに使えるプロジェクト構造が得られ、その中には2種類の重要なテストが含まれます：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;単体テスト :&amp;lt;/strong&amp;gt;位置している`src/test`, これらは、私たちのプラグインの孤立したコンポーネントを検証することを可能にします。たとえば、タスクの内部ロジックや拡張機能の設定などです。これらは高速であり、Gradle の完全な実行を必要としません。&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;機能テスト :&amp;lt;/strong&amp;gt;にある`src/functionalTest`, 彼らは使う`GradleRunner`一時的なテストプロジェクトで完全なGradleビルドを実行するために。これにより、制御された環境でプラグインの実際の動作を確認できます。&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_2_私たちの最初のtddサイクル_タスクを記録する&amp;quot;&amp;gt;2. 私たちの最初のTDDサイクル : タスクを記録する&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;私たちの最初の要件はシンプルです：プラグインは、名前が付けられたタスクを記録する必要があります`printSiteConfig`。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_2_1_まずテストする_失敗するテスト&amp;quot;&amp;gt;2.1. まずテストする (失敗するテスト)&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;TDDに従い、まず、このタスクの存在を確認するテストを書きます。 では`SiteBakerPluginTest.kt`(私たちのユニットテストファイル)、追加します：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-kotlin hljs&amp;quot; data-lang=&amp;quot;kotlin&amp;quot;&amp;gt;@Test
fun `plugin registers task`() {
    // Créer un projet de test en mémoire
    val project = ProjectBuilder.builder().build()
    project.plugins.apply(&amp;quot;com.cheroliv.site-baker&amp;quot;)

    // Vérifier que la tâche a bien été enregistrée
    assertNotNull(project.tasks.findByName(&amp;quot;printSiteConfig&amp;quot;))
}&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;このテストが失敗するのは、私たちがまだプラグインにコードを書いていないからです。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_2_2_コードの次に_テストを通す&amp;quot;&amp;gt;2.2. コードの次に (テストを通す)&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;今、私たちは必要最小限のコードを書いています`SiteBakerPlugin.kt`テストが通るように :&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-kotlin hljs&amp;quot; data-lang=&amp;quot;kotlin&amp;quot;&amp;gt;class SiteBakerPlugin: Plugin&amp;amp;lt;Project&amp;amp;gt; {
    override fun apply(project: Project) {
        // Enregistrer une tâche simple
        project.tasks.register(&amp;quot;printSiteConfig&amp;quot;) { task -&amp;amp;gt;
            // ... la logique de la tâche viendra plus tard
        }
    }
}&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;テストを再実行し、合格しています。最初の機能は検証されています。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_3_第2サイクル_tdd_dsl拡張を追加&amp;quot;&amp;gt;3. 第2サイクル TDD : DSL拡張を追加&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;次の要件は、ユーザーがDSLブロックを使って私たちのプラグインを設定できるようにすること`build.gradle.kts`. 私たちはブロックが欲しい`site { &amp;amp;#8230;&amp;amp;#8203; }`設定パスを指定できる場所。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_3_1_最初のテスト&amp;quot;&amp;gt;3.1. 最初のテスト&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;�拡張機能が正しく動作することを確認するためのテストを追加しています。`site`よく記録されており、そこに値を割り当てることができる。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-kotlin hljs&amp;quot; data-lang=&amp;quot;kotlin&amp;quot;&amp;gt;@Test
fun `plugin registers extension`() {
    val project = ProjectBuilder.builder().build()
    project.plugins.apply(&amp;quot;com.cheroliv.site-baker&amp;quot;)

    // Récupérer l&amp;#39;extension et lui affecter une valeur
    project.extensions
        .findByType(SiteExtension::class.java)!!
        .configPath
        .set(&amp;quot;config.yml&amp;quot;)

    // Vérifier que la valeur a bien été prise en compte
    assertEquals(
        &amp;quot;config.yml&amp;quot;,
        project.extensions.findByType(SiteExtension::class.java)?.configPath?.get()
    )
}&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;このテストは失敗しますなぜならクラスが`SiteExtension`拡張機能の登録も存在しない&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_3_2_コードその後&amp;quot;&amp;gt;3.2. コードその後&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;私たちはクラスを作ります`SiteBakerExtension.kt`と私たちは更新します`SiteBakerPlugin.kt`:&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-kotlin hljs&amp;quot; data-lang=&amp;quot;kotlin&amp;quot;&amp;gt;// SiteBakerExtension.kt
open class SiteExtension @Inject constructor(objects: ObjectFactory) {
    val configPath: Property&amp;amp;lt;String&amp;amp;gt; = objects.property(String::class.java)
}

// SiteBakerPlugin.kt
class SiteBakerPlugin: Plugin&amp;amp;lt;Project&amp;amp;gt; {
    override fun apply(project: Project) {
        // Enregistrer l&amp;#39;extension
        val extension = project.extensions.create(&amp;quot;site&amp;quot;, SiteExtension::class.java)

        project.tasks.register(&amp;quot;printSiteConfig&amp;quot;) { task -&amp;amp;gt;
            task.doLast {
                // On utilisera l&amp;#39;extension plus tard
            }
        }
    }
}&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;テストが再びパスしました。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_4_機能テスト統合の検証&amp;quot;&amp;gt;4. 機能テスト：統合の検証&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;ユニットのテストが終わった今、実際のビルドですべてが正しく連携することを確認する必要があります。これは機能テストの役割です。[something]における`SiteBakerPluginFunctionalTest.kt`。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_4_1_統合テスト_制御された環境を作成する&amp;quot;&amp;gt;4.1. 統合テスト : 制御された環境を作成する&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;このテストは、私たちのプラグインを使用した実際のプロジェクトをシミュレートします。信頼性を持たせるために、これはでなければなりません。&amp;lt;strong&amp;gt;気密&amp;lt;/strong&amp;gt;,つまり、システム上に存在するファイルに依存してはならない。必要となる実行条件はすべて自分自身で作らなければならない。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;テストはしたがって：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;olist arabic&amp;quot;&amp;gt;
&amp;lt;ol class=&amp;quot;arabic&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;作る`build.gradle.kts`私たちのプラグインとそのDSLを使用するテスト。&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;設定ファイルを作成&amp;lt;/strong&amp;gt;(&amp;lt;code&amp;gt;managed-jbake-context.yml&amp;lt;/code&amp;gt;) プラグインが読み込むべきものです。これはテストの堅牢性にとって重要なステップです。&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;タスクの実行`printSiteConfig`経由して`GradleRunner`.&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;ビルドの出力が正しいことを確認する。&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ol&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;この構成ファイルを実行のたびにコピーまたは作成することで、テストが&amp;lt;strong&amp;gt;再現可能&amp;lt;/strong&amp;gt;外部の状態に依存せず。これによりファイルの読み込みに関連する可能性のある回帰から私たちのテストを守ります。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-kotlin hljs&amp;quot; data-lang=&amp;quot;kotlin&amp;quot;&amp;gt;@Test fun `can run task with DSL`() {
    // 1. Créer un build.gradle.kts de test
    buildFile.writeText(&amp;quot;&amp;quot;&amp;quot;
        plugins { id(&amp;quot;com.cheroliv.site-baker&amp;quot;) }
        site { configPath = &amp;quot;managed-jbake-context.yml&amp;quot; }
    &amp;quot;&amp;quot;&amp;quot;.trimIndent())

    // 2. Créer le fichier de configuration pour un test contrôlé
    val configFile = File(projectDir, &amp;quot;managed-jbake-context.yml&amp;quot;)
    configFile.writeText(&amp;quot;site: { title: &amp;#39;Mon Site de Test&amp;#39; }&amp;quot;) // Contenu YAML simple

    // 3. Exécuter la build
    val runner = GradleRunner.create()
    runner.withPluginClasspath()
    runner.withArguments(&amp;quot;printSiteConfig&amp;quot;)
    runner.withProjectDir(projectDir) // Spécifier le répertoire du projet de test
    val result = runner.build()

    // 4. Vérifier la sortie
    assertTrue(result.output.contains(&amp;quot;Site config path: managed-jbake-context.yml&amp;quot;))
}&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;このテストはタスクが続く間失敗します`printSiteConfig`拡張機能の値を実際には使用しません。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_4_2_ロジックを最終化する&amp;quot;&amp;gt;4.2. ロジックを最終化する&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;タスクを更新しています中で`SiteBakerPlugin.kt`設定された値を表示するために：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-kotlin hljs&amp;quot; data-lang=&amp;quot;kotlin&amp;quot;&amp;gt;project.tasks.register(&amp;quot;printSiteConfig&amp;quot;) { task -&amp;amp;gt;
    task.doLast {
        println(&amp;quot;Site config path: ${extension.configPath.get()}&amp;quot;)
    }
}&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;すべてのテスト（単体テストおよび機能テスト）は、今ではパスしています。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_結論&amp;quot;&amp;gt;結論&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;TDDアプローチに従い、私たちはインクリメンタルかつ安全にプラグインを構築しました。各小さな機能は、すぐにテストによって検証されます。高速なユニットテストから、完全な統合を検証する機能テストまでです。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;テストを機能的にするために注意を払って&amp;lt;strong&amp;gt;気密の&amp;lt;/strong&amp;gt;— 必要な構成ファイルをプログラムで作成することで — 私たちは極めて強固な安全ネットを築きます。この厳格さは、回帰を効果的に防ぎ、その後、YAML構成ファイルのパースなど、より複雑な機能を追加する際に大きな自信を与えてくれます。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;この堅牢なテスト基盤は、プラグインの保守および将来の進化において最も貴重な資産です。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;</description>
        </item><item>
            <title>記事1 : gradle initコマンドでAからZまでGradleプラグインを作成する</title>
            <link >https://cheroliv.com/blog/2025/0089_creation_projet_plugin_gradle_post.html</link>
            <pubDate>Tue, 23 Sep 2025 00:00:00 +0000</pubDate>
            <guid isPermaLink="false">blog/2025/0089_creation_projet_plugin_gradle_post.html</guid>
            <description>&amp;lt;div id=&amp;quot;toc&amp;quot; class=&amp;quot;toc&amp;quot;&amp;gt;
&amp;lt;div id=&amp;quot;toctitle&amp;quot;&amp;gt;Sommaire&amp;lt;/div&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel1&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_はじめに&amp;quot;&amp;gt;はじめに&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_ステップ_1_プロジェクト_アシスタントを起動する&amp;quot;&amp;gt;ステップ 1 : プロジェクト アシスタントを起動する&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_ステップ_2_生成された構造を理解する&amp;quot;&amp;gt;ステップ 2 : 生成された構造を理解する&amp;lt;/a&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel2&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_重要なファイルとフォルダー&amp;quot;&amp;gt;重要なファイルとフォルダー&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_はじめに&amp;quot;&amp;gt;はじめに&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;対象: 初心者から中級者までの Gradle 開発者&amp;lt;/div&amp;gt;
&amp;lt;p&amp;gt;Gradleプラグインの新しいプロジェクトを始めることは恐ろしく見えるかもしれません。幸いなことに、Gradleは強力なインタラクティブなアシスタントを提供します、そのタスクは`init`, このツールは完全で綺麗かつすぐに使えるプロジェクト構造を生成します。このガイドでは、このツールを使って健全なプラグインベースを作成する方法、構造を説明し、そして最初のビルドタスクを実行する方法を示します。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_ステップ_1_プロジェクト_アシスタントを起動する&amp;quot;&amp;gt;ステップ 1 : プロジェクト アシスタントを起動する&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;コマンド`gradle init`これは出発点です。これにより、プロジェクトを設定するための質問を一連行うコマンドラインアシスタントが起動されます。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;空のフォルダーでターミナルを開き、次のコマンドを実行してください：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;gradle init&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;アシスタントが案内します。Kotlin で書かれた Gradle プラグインの選択肢は次の通りです：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;olist arabic&amp;quot;&amp;gt;
&amp;lt;ol class=&amp;quot;arabic&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;生成するプロジェクトの種類を選択:&amp;lt;/strong&amp;gt;選んでください`Gradle plugin`.&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;実装言語を選択:&amp;lt;/strong&amp;gt;選んでください`Kotlin`。&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;ビルドスクリプトDSLを選択:&amp;lt;/strong&amp;gt;選んでください`Kotlin`.&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;プロジェクト名:&amp;lt;/strong&amp;gt;プロジェクトの名前を入力してください（例：&amp;lt;code&amp;gt;site-baker&amp;lt;/code&amp;gt;).&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;プラグイン ID:&amp;lt;/strong&amp;gt;あなたのプラグインに一意の識別子を付けてください (例：&amp;lt;code&amp;gt;com.cheroliv.site-baker&amp;lt;/code&amp;gt;).&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;プラグインクラス:&amp;lt;/strong&amp;gt;実装クラスの名前を指定してください（例:`com.cheroliv.SiteBakerPlugin`).&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ol&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;完了すると、Gradleは完全なファイルツリーを生成します。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;初期化プロセスの図&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
start
:Lancer `gradle init`;
:Choisir &amp;quot;Gradle プラグイン&amp;quot;;
:Choisir &amp;quot;コトリン&amp;quot; (langage);
:Choisir &amp;quot;コトリン&amp;quot; (DSL);
:Saisir nom, ID, et classe;
:Projet généré;
stop
@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_ステップ_2_生成された構造を理解する&amp;quot;&amp;gt;ステップ 2 : 生成された構造を理解する&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;アシスタントはマルチモジュールのプロジェクト構造を作成し、ルートプロジェクトをプラグインのソースコードから分離します。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-text hljs&amp;quot; data-lang=&amp;quot;text&amp;quot;&amp;gt;.
├── gradle/
│   └── wrapper/
│       ├── gradle-wrapper.jar
│       └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── plugin/
│   ├── build.gradle.kts
│   └── src/
│       ├── main/
│       │   └── kotlin/
│       │       └── com/cheroliv/SiteBakerPlugin.kt
│       ├── test/
│       │   └── kotlin/
│       │       └── com/cheroliv/SiteBakerPluginTest.kt
│       └── functionalTest/
│           └── kotlin/
│               └── com/cheroliv/SiteBakerPluginFunctionalTest.kt
└── settings.gradle.kts&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_重要なファイルとフォルダー&amp;quot;&amp;gt;重要なファイルとフォルダー&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;code&amp;gt;settings.gradle.kts&amp;lt;/code&amp;gt;: このルートにあるファイルは、ビルドに含まれるモジュールを定義します。ここでは、サブプロジェクトを含みます。&amp;lt;code&amp;gt;plugin&amp;lt;/code&amp;gt;.&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;[source,kotlin] ---- rootProject.name = &amp;quot;site-baker include(&amp;quot;plugin&amp;quot;) ----&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;</description>
        </item><item>
            <title>記事 0 : Gradleプラグインを作成するための環境設定</title>
            <link >https://cheroliv.com/blog/2025/0088_environnement_plugin_gradle_post.html</link>
            <pubDate>Mon, 22 Sep 2025 00:00:00 +0000</pubDate>
            <guid isPermaLink="false">blog/2025/0088_environnement_plugin_gradle_post.html</guid>
            <description>&amp;lt;div id=&amp;quot;toc&amp;quot; class=&amp;quot;toc&amp;quot;&amp;gt;
&amp;lt;div id=&amp;quot;toctitle&amp;quot;&amp;gt;Sommaire&amp;lt;/div&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel1&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_導入&amp;quot;&amp;gt;導入&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_1_jdk_gradleエンジン&amp;quot;&amp;gt;1. JDK: Gradleエンジン&amp;lt;/a&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel2&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_どのバージョンを選びますか&amp;quot;&amp;gt;どのバージョンを選びますか？&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_sdkman_を介したインストール_推奨&amp;quot;&amp;gt;SDKMAN! を介したインストール (推奨)&amp;lt;/a&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel3&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_sdkmanをインストール&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;SDKMAN!をインストール&amp;lt;/strong&amp;gt;&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_jdk_のバージョンをインストールする&amp;quot;&amp;gt;JDK のバージョンをインストールする&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_インストールを確認&amp;quot;&amp;gt;インストールを確認&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_2_ide_intellij_idea&amp;quot;&amp;gt;2. IDE : IntelliJ IDEA&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_3_gradle_ビルドツール&amp;quot;&amp;gt;3. Gradle : ビルドツール&amp;lt;/a&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel2&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_sdkmanによるインストール&amp;quot;&amp;gt;SDKMAN!によるインストール&amp;lt;/a&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel3&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_gradleをインストールする&amp;quot;&amp;gt;Gradleをインストールする&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_インストールを確認する&amp;quot;&amp;gt;インストールを確認する&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_4_jbake_静的サイトジェネレーター&amp;quot;&amp;gt;4. JBake : 静的サイトジェネレーター&amp;lt;/a&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel2&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_sdkman_を使ったインストール&amp;quot;&amp;gt;SDKMAN! を使ったインストール&amp;lt;/a&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel3&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_jbakeをインストール&amp;quot;&amp;gt;JBakeをインストール&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_インストールを確認_2&amp;quot;&amp;gt;インストールを確認&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_5_gradleラッパー絶対的なベストプラクティス&amp;quot;&amp;gt;5. Gradleラッパー：絶対的なベストプラクティス&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_6_docker_と_portainer_再現可能なビルド_オプション&amp;quot;&amp;gt;6. Docker と Portainer : 再現可能なビルド (オプション)&amp;lt;/a&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel2&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_docker_engineのインストール&amp;quot;&amp;gt;Docker Engineのインストール&amp;lt;/a&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel3&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_dockerを公式スクリプトでインストール&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;Dockerを公式スクリプトでインストール：&amp;lt;/strong&amp;gt;&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_dockerをsudoなしで管理する推奨&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;Dockerを`sudo`なしで管理する（推奨）：&amp;lt;/strong&amp;gt;&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_portainer_gui_を使って_docker_を管理&amp;quot;&amp;gt;Portainer (GUI) を使って Docker を管理&amp;lt;/a&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel3&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_portainerのデータ用ボリュームを作成してください&amp;quot;&amp;gt;Portainerのデータ用ボリュームを作成してください：&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_portainer_コンテナーを起動&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;Portainer コンテナーを起動：&amp;lt;/strong&amp;gt;&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_結論&amp;quot;&amp;gt;結論&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_導入&amp;quot;&amp;gt;導入&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;対象者 : Gradle プラグインの作成に取り組みたい開発者&amp;lt;/div&amp;gt;
&amp;lt;p&amp;gt;Gradleプラグインを効率的に開発するためには、適切に設定された開発環境が不可欠です。 良いセットアップは時間を節約し、フラストレーションを減らし、ビルドの一貫性を確保します。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;olist arabic&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;このガイドは4つの重要な柱に焦点を当てています：&amp;lt;/div&amp;gt;
&amp;lt;ol class=&amp;quot;arabic&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;Le &amp;lt;strong&amp;gt;JDK&amp;lt;/strong&amp;gt;(Java Development Kit)、なぜならGradleとJBakeはJVM上で実行されます。&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;Un &amp;lt;strong&amp;gt;統合開発環境&amp;lt;/strong&amp;gt;モダンな(IntelliJ IDEA)で、KotlinとGradleのサポートが良い。&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;Gradle&amp;lt;/strong&amp;gt;自身で、プロジェクトを初期化するために。&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;JBake&amp;lt;/strong&amp;gt;, 私たちの静的サイトのエンジン。&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ol&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;開発環境のコンポーネント&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
!theme plain
node &amp;quot;開発者の機械&amp;quot; {
  component &amp;quot;JDK (JVM)&amp;quot; as JDK
  component &amp;quot;IntelliJ IDEA&amp;quot; as IDE
  component &amp;quot;Gradle (グローバル)&amp;quot; as Gradle
  component &amp;quot;JBake (グローバル)&amp;quot; as JBake

  IDE --&amp;amp;gt; JDK : utilise
  Gradle --&amp;amp;gt; JDK : utilise
  JBake --&amp;amp;gt; JDK : utilise
}
@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_1_jdk_gradleエンジン&amp;quot;&amp;gt;1. JDK: Gradleエンジン&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;Gradle は Java 仮想マシン (JVM) 上で実行されるアプリケーションです。 したがって、JDKのインストールは絶対に必要な前提条件です。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_どのバージョンを選びますか&amp;quot;&amp;gt;どのバージョンを選びますか？&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;JavaのLTS(Long-Term Support)バージョンを使用することをお勧めします。 現在,&amp;lt;strong&amp;gt;JDK 17&amp;lt;/strong&amp;gt; ou &amp;lt;strong&amp;gt;JDK 21&amp;lt;/strong&amp;gt;非常に良い選択肢です。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_sdkman_を介したインストール_推奨&amp;quot;&amp;gt;SDKMAN! を介したインストール (推奨)&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;SDKMAN!は、JavaやGradleを含む多数のSDKのバージョンを管理するための優れたツールです。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect3&amp;quot;&amp;gt;
&amp;lt;h4 id=&amp;quot;_sdkmanをインストール&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;SDKMAN!をインストール&amp;lt;/strong&amp;gt;&amp;lt;/h4&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;curl -s &amp;quot;https://get.sdkman.io&amp;quot; | bash source &amp;quot;$HOME/.sdkman/bin/sdkman-init.sh&amp;quot;&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect3&amp;quot;&amp;gt;
&amp;lt;h4 id=&amp;quot;_jdk_のバージョンをインストールする&amp;quot;&amp;gt;JDK のバージョンをインストールする&amp;lt;/h4&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;# Pour lister les versions de Java disponibles sdk list java

# Pour installer Java 17 (par exemple, la distribution Temurin)
sdk install java 17.0.8-tem&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect3&amp;quot;&amp;gt;
&amp;lt;h4 id=&amp;quot;_インストールを確認&amp;quot;&amp;gt;インストールを確認&amp;lt;/h4&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;java -version&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;インストールしたばかりのバージョンが表示されるはずです。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_2_ide_intellij_idea&amp;quot;&amp;gt;2. IDE : IntelliJ IDEA&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;Gradle プラグインの開発に Kotlin DSL を使用して&amp;lt;strong&amp;gt;IntelliJ IDEA&amp;lt;/strong&amp;gt;選択のツールです。 Gradle と Kotlin との統合は比類ない。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;コミュニティエディション :&amp;lt;/strong&amp;gt;無料で、開始するには十分すぎるほどです。&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;アルティメットエディション：&amp;lt;/strong&amp;gt;有料です。ウェブ開発とデータベースのための高度な機能を提供します。&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;JetBrainsのサイトからご自身に合ったバージョンをダウンロードしてください：https://www.jetbrains.com/idea/download/&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;IDEは自動的にあなたのファイルを検出します`build.gradle.kts` et &amp;lt;code&amp;gt;settings.gradle.kts&amp;lt;/code&amp;gt;, 強力な自動補完、コードナビゲーション、統合されたデバッグツールを提供します。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_3_gradle_ビルドツール&amp;quot;&amp;gt;3. Gradle : ビルドツール&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;各プロジェクトがGradle Wrapperを通じて自身のGradleバージョンを使用する場合でも、新しいプロジェクトの初期化などのタスクのためにグローバルなGradleのインストールがあると便利です (&amp;lt;code&amp;gt;gradle init&amp;lt;/code&amp;gt;).&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_sdkmanによるインストール&amp;quot;&amp;gt;SDKMAN!によるインストール&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;JDKのように、SDKMAN!はGradleのインストールを簡単にします。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect3&amp;quot;&amp;gt;
&amp;lt;h4 id=&amp;quot;_gradleをインストールする&amp;quot;&amp;gt;Gradleをインストールする&amp;lt;/h4&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;sdk install gradle&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect3&amp;quot;&amp;gt;
&amp;lt;h4 id=&amp;quot;_インストールを確認する&amp;quot;&amp;gt;インストールを確認する&amp;lt;/h4&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;gradle -v&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;このコマンドは、使用されている Gradle、Kotlin、Groovy、および JDK のバージョンを表示します。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_4_jbake_静的サイトジェネレーター&amp;quot;&amp;gt;4. JBake : 静的サイトジェネレーター&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;JBakeは、私たちがソースファイル（このファイルのように）を静的なウェブサイトに変換するために使用するツールです。 ローカルにインストールしておくと、変更のプレビューが便利です。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_sdkman_を使ったインストール&amp;quot;&amp;gt;SDKMAN! を使ったインストール&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;他のツールと同様に、SDKMAN! が最もシンプルな方法です。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect3&amp;quot;&amp;gt;
&amp;lt;h4 id=&amp;quot;_jbakeをインストール&amp;quot;&amp;gt;JBakeをインストール&amp;lt;/h4&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;sdk install jbake&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect3&amp;quot;&amp;gt;
&amp;lt;h4 id=&amp;quot;_インストールを確認_2&amp;quot;&amp;gt;インストールを確認&amp;lt;/h4&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;jbake -v&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;このコマンドはJBakeのバージョンと、それが使用するJava環境の情報を表示します。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_5_gradleラッパー絶対的なベストプラクティス&amp;quot;&amp;gt;5. Gradleラッパー：絶対的なベストプラクティス&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;プロジェクトを作成したら（これは次の記事で説明します）、もうグローバルコマンドを使用すべきではありません`gradle`。 代わりに、あなたはそれを使います&amp;lt;strong&amp;gt;Gradleラッパー&amp;lt;/strong&amp;gt;(&amp;lt;code&amp;gt;./gradlew&amp;lt;/code&amp;gt;), あなたのプロジェクトに組み込まれたスクリプト。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;なぜ？&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;再現性：&amp;lt;/strong&amp;gt;ラッパーは、プロジェクトで作業しているすべての人（CI/CDサーバーを含む）が正確に同じものを使用することを保証します。&amp;lt;strong&amp;gt;同じバージョンのGradle&amp;lt;/strong&amp;gt;, これにより異なる環境によるビルドエラーが解消されます。&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;シンプルさ：&amp;lt;/strong&amp;gt;プロジェクトに貢献するためにGradleを手動でインストールする必要はありません。&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;リポジトリをクローンして実行するだけ`./gradlew`.&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;典型的なコマンドはこのように：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;# Ne pas faire : gradle build
# À faire :
./gradlew build&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_6_docker_と_portainer_再現可能なビルド_オプション&amp;quot;&amp;gt;6. Docker と Portainer : 再現可能なビルド (オプション)&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;プラグインを書く上で厳密に必要というわけではないが、Docker と Portainer はモダンな DevOps ツールであり、再現可能なビルドの作成と環境の管理を大幅に容易にします。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_docker_engineのインストール&amp;quot;&amp;gt;Docker Engineのインストール&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;Dockerを使うと、アプリケーションとその依存関係をコンテナにパッケージングできます。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect3&amp;quot;&amp;gt;
&amp;lt;h4 id=&amp;quot;_dockerを公式スクリプトでインストール&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;Dockerを公式スクリプトでインストール：&amp;lt;/strong&amp;gt;&amp;lt;/h4&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;curl -fsSL https://get.docker.com -o get-docker.sh sudo sh get-docker.sh&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect3&amp;quot;&amp;gt;
&amp;lt;h4 id=&amp;quot;_dockerをsudoなしで管理する推奨&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;Dockerを`sudo`なしで管理する（推奨）：&amp;lt;/strong&amp;gt;&amp;lt;/h4&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;あなたのユーザーをグループに追加してください`docker`。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;sudo usod -aG docker $USER&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;admonitionblock important&amp;quot;&amp;gt;
&amp;lt;table&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;icon&amp;quot;&amp;gt;
&amp;lt;i class=&amp;quot;fa icon-important&amp;quot; title=&amp;quot;Important&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;
&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;content&amp;quot;&amp;gt;

&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/table&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;docker run hello-world&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_portainer_gui_を使って_docker_を管理&amp;quot;&amp;gt;Portainer (GUI) を使って Docker を管理&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;Portainerは、Dockerコンテナを管理するための軽量なウェブインターフェース。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect3&amp;quot;&amp;gt;
&amp;lt;h4 id=&amp;quot;_portainerのデータ用ボリュームを作成してください&amp;quot;&amp;gt;Portainerのデータ用ボリュームを作成してください：&amp;lt;/h4&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;docker volume create portainer_data&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect3&amp;quot;&amp;gt;
&amp;lt;h4 id=&amp;quot;_portainer_コンテナーを起動&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;Portainer コンテナーを起動：&amp;lt;/strong&amp;gt;&amp;lt;/h4&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;docker run -d -p 8000:8000 -p 9443:9443 --name portainer --restart=always -v /var/run/docker.sock:/var/run/docker.sock -v portainer_data:/data portainer/portainer-ce:latest&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;あなたは今、Portainerのインターフェースにアクセスできます`https://localhost:9443`.&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_結論&amp;quot;&amp;gt;結論&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;あなたの環境は今準備が整いました！ JDK、最適なIDE、Gradle、JBakeを持っています。 Dockerを追加すると、コンテナ化された再現可能なビルドを作成する準備も整います。 このしっかりした基盤があれば、本質に集中できます：強力で便利なプラグインの開発に。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;次の記事では、そのコマンドを使用します。`gradle init`私たちの最初のプラグインプロジェクトの構造を生成するために。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;</description>
        </item><item>
            <title>CI/CD Python – 第3部：Poetry、Docker、高度な出版でさらに進む</title>
            <link >https://cheroliv.com/blog/2025/0087_pypi_cicd_part_3_post.html</link>
            <pubDate>Sat, 19 Jul 2025 00:00:00 +0000</pubDate>
            <guid isPermaLink="false">blog/2025/0087_pypi_cicd_part_3_post.html</guid>
            <description>&amp;lt;div id=&amp;quot;toc&amp;quot; class=&amp;quot;toc&amp;quot;&amp;gt;
&amp;lt;div id=&amp;quot;toctitle&amp;quot;&amp;gt;Table of Contents&amp;lt;/div&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel1&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_poetry_との統合&amp;quot;&amp;gt;Poetry との統合&amp;lt;/a&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel2&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_poetryのインストール&amp;quot;&amp;gt;Poetryのインストール&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_プロジェクトの初期化&amp;quot;&amp;gt;プロジェクトの初期化&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_依存関係の追加とインストール&amp;quot;&amp;gt;依存関係の追加とインストール&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_poetryを使った公開&amp;quot;&amp;gt;Poetryを使った公開&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_dockerを使った再現可能なビルド&amp;quot;&amp;gt;Dockerを使った再現可能なビルド&amp;lt;/a&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel2&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_dockerfileの例&amp;quot;&amp;gt;Dockerfileの例&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_github_actionsへの統合&amp;quot;&amp;gt;GitHub Actionsへの統合&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_条件付き公開&amp;quot;&amp;gt;条件付き公開&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_renovate_と_dependabot_を使った依存関係の自動化&amp;quot;&amp;gt;Renovate と Dependabot を使った依存関係の自動化&amp;lt;/a&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel2&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_dependabot&amp;quot;&amp;gt;Dependabot&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_リノベート&amp;quot;&amp;gt;リノベート&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_plantuml図&amp;quot;&amp;gt;PlantUML図&amp;lt;/a&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel2&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_ユースケース_高度なcicd&amp;quot;&amp;gt;ユースケース – 高度なCI/CD&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_シーケンス_条件付き公開&amp;quot;&amp;gt;シーケンス – 条件付き公開&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_ステータス_cicd_パイプライン&amp;quot;&amp;gt;ステータス – CI/CD パイプライン&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_デプロイメント_cicdアーキテクチャ&amp;quot;&amp;gt;デプロイメント – CI/CDアーキテクチャ&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_結論&amp;quot;&amp;gt;結論&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div id=&amp;quot;preamble&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;このシリーズの最初の2つの部分では、私たちは： - GitHub Actions と PyPI を使用して Python アプリケーションの機能的な CI/CD パイプラインを構築しました。 - このパイプラインをマルチバージョンテスト、Test PyPIによる段階的リリース、品質およびセキュリティツールで工業化しました。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;この第三部では、私たちは行きます&amp;lt;strong&amp;gt;PyPI への単なる公開を超えて&amp;lt;/strong&amp;gt;を構築するために、完全で堅牢かつプロフェッショナルな CI/CD チェーンを作るために : - &amp;lt;strong&amp;gt;詩&amp;lt;/strong&amp;gt;モダンなパッケージングと依存関係の最適化された管理のために - &amp;lt;strong&amp;gt;ドッカー&amp;lt;/strong&amp;gt;再現可能でマルチプラットフォームなビルドを作成するために。 - &amp;lt;strong&amp;gt;条件付き出版&amp;lt;/strong&amp;gt;リリース候補などのシナリオを管理するために - &amp;lt;strong&amp;gt;自動化ツール&amp;lt;/strong&amp;gt;(Renovate, Dependabot) パイプラインを最新の状態に保つために労力をかけずに。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_poetry_との統合&amp;quot;&amp;gt;Poetry との統合&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;Poetry は従来のパッケージングツール (setup.py, requirements.txt) を置き換え、依存関係とビルドの管理を一元化する中に`pyproject.toml`.&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_poetryのインストール&amp;quot;&amp;gt;Poetryのインストール&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-shell hljs&amp;quot; data-lang=&amp;quot;shell&amp;quot;&amp;gt;# Installer Poetry
curl -sSL https://install.python-poetry.org | python3 -
# Vérifier la version
poetry --version&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_プロジェクトの初期化&amp;quot;&amp;gt;プロジェクトの初期化&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-shell hljs&amp;quot; data-lang=&amp;quot;shell&amp;quot;&amp;gt;# Initialiser un nouveau projet avec Poetry
poetry init
# Suivre l&amp;#39;assistant pour renseigner : nom, version, description, licence, dépendances.&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;これはファイルを生成します`pyproject.toml`:&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-toml hljs&amp;quot; data-lang=&amp;quot;toml&amp;quot;&amp;gt;[tool.poetry]
name = &amp;quot;playlist-downloader&amp;quot;
version = &amp;quot;0.1.0&amp;quot;
description = &amp;quot;CLI tool for managing YouTube playlists&amp;quot;
authors = [&amp;quot;Christophe Hérolivier &amp;amp;lt;cheroliv@example.com&amp;amp;gt;&amp;quot;]

[tool.poetry.dependencies]
python = &amp;quot;&amp;amp;gt;=3.8&amp;quot;
typer = &amp;quot;^0.9.0&amp;quot;
yt-dlp = &amp;quot;^2023.7.6&amp;quot;
google-api-python-client = &amp;quot;^2.0.0&amp;quot;
google-auth-oauthlib = &amp;quot;^1.0.0&amp;quot;

[tool.poetry.group.dev.dependencies]
pytest = &amp;quot;^7.0&amp;quot;
mypy = &amp;quot;^1.0&amp;quot;
bandit = &amp;quot;^1.7&amp;quot;
safety = &amp;quot;^2.3&amp;quot;
black = &amp;quot;^23.0&amp;quot;
ruff = &amp;quot;^0.1&amp;quot;&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_依存関係の追加とインストール&amp;quot;&amp;gt;依存関係の追加とインストール&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-shell hljs&amp;quot; data-lang=&amp;quot;shell&amp;quot;&amp;gt;poetry add typer yt-dlp google-api-python-client google-auth-oauthlib
poetry add --group dev pytest mypy black bandit safety ruff&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_poetryを使った公開&amp;quot;&amp;gt;Poetryを使った公開&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;Poetry はネイティブに公開を管理します :&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-shell hljs&amp;quot; data-lang=&amp;quot;shell&amp;quot;&amp;gt;# Publication sur Test PyPI
poetry publish --build --repository test-pypi

# Publication sur PyPI
poetry publish --build&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;このコマンドは自動的に存在する情報を使用する`pyproject.toml`。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_dockerを使った再現可能なビルド&amp;quot;&amp;gt;Dockerを使った再現可能なビルド&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;開発、CI/CD、本番で同じ実行を保証するために、DockerはPoetryと完全に統合されます。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_dockerfileの例&amp;quot;&amp;gt;Dockerfileの例&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-dockerfile hljs&amp;quot; data-lang=&amp;quot;dockerfile&amp;quot;&amp;gt;FROM python:3.11-slim

WORKDIR /app
COPY pyproject.toml poetry.lock ./
RUN pip install poetry
RUN poetry install --no-root --only main

COPY . .

CMD [&amp;quot;poetry&amp;quot;, &amp;quot;run&amp;quot;, &amp;quot;python&amp;quot;, &amp;quot;cli.py&amp;quot;]&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;これは保証します： - 凍結されたPython環境。 経由でロックされた依存関係`poetry.lock`. - Dockerをサポートするあらゆるシステムで実行可能なイメージ。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_github_actionsへの統合&amp;quot;&amp;gt;GitHub Actionsへの統合&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-yaml hljs&amp;quot; data-lang=&amp;quot;yaml&amp;quot;&amp;gt;name: Docker Build

on:
  push:
    branches: [main]

jobs:
  build-docker:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Build Docker image
        run: docker build -t ghcr.io/${{ github.repository }}:latest .
      - name: Push Docker image
        run: docker push ghcr.io/${{ github.repository }}:latest&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_条件付き公開&amp;quot;&amp;gt;条件付き公開&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;プロフェッショナルなパイプラインでは、特定の場合のみ公開できる必要があります : - テストPyPI向けリリース候補。 - 安定版をPyPIに - Builds Docker トリガーのみ`main`.&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-yaml hljs&amp;quot; data-lang=&amp;quot;yaml&amp;quot;&amp;gt;- name: Publish to Test PyPI
  if: contains(github.ref, &amp;#39;-rc&amp;#39;)
  run: poetry publish --build --repository test-pypi

- name: Publish to PyPI
  if: startsWith(github.ref, &amp;#39;refs/tags/v&amp;#39;)
  run: poetry publish --build&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;このアプローチは意図しない公開を防ぎます。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_renovate_と_dependabot_を使った依存関係の自動化&amp;quot;&amp;gt;Renovate と Dependabot を使った依存関係の自動化&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;依存関係が古くなるのを防ぐため、自動更新ツールを組み込んでください。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_dependabot&amp;quot;&amp;gt;Dependabot&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-yaml hljs&amp;quot; data-lang=&amp;quot;yaml&amp;quot;&amp;gt;version: 2
updates:
  - package-ecosystem: &amp;quot;pip&amp;quot;
    directory: &amp;quot;/&amp;quot;
    schedule:
      interval: &amp;quot;weekly&amp;quot;
  - package-ecosystem: &amp;quot;github-actions&amp;quot;
    directory: &amp;quot;/&amp;quot;
    schedule:
      interval: &amp;quot;weekly&amp;quot;&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;Dependabotは毎週、PythonおよびGitHub Actionsの依存関係を更新するためにPRを開きます。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_リノベート&amp;quot;&amp;gt;リノベート&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-json hljs&amp;quot; data-lang=&amp;quot;json&amp;quot;&amp;gt;{
  &amp;quot;extends&amp;quot;: [&amp;quot;config:base&amp;quot;],
  &amp;quot;packageRules&amp;quot;: [
    {
      &amp;quot;matchManagers&amp;quot;: [&amp;quot;pip&amp;quot;],
      &amp;quot;groupName&amp;quot;: &amp;quot;python-dependencies&amp;quot;,
      &amp;quot;schedule&amp;quot;: [&amp;quot;before 6am on monday&amp;quot;]
    }
  ]
}&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;Renovateはより細かい制御を可能にします：依存関係のグループ化、スケジューリング、および高度なルール。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_plantuml図&amp;quot;&amp;gt;PlantUML図&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_ユースケース_高度なcicd&amp;quot;&amp;gt;ユースケース – 高度なCI/CD&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
actor Developer
actor GitHub as &amp;quot;GitHub アクション&amp;quot;
actor PyPI
actor DockerRegistry as &amp;quot;Docker レジストリ&amp;quot;
actor Automation as &amp;quot;リノベート/Dependabot&amp;quot;

Developer --&amp;amp;gt; (Push code)
(Trigger CI) --&amp;amp;gt; GitHub
GitHub --&amp;amp;gt; (Run Tests &amp;amp;amp; Lint)
GitHub --&amp;amp;gt; (Build Docker Image)
GitHub --&amp;amp;gt; DockerRegistry
GitHub --&amp;amp;gt; (Publish to Test PyPI)
GitHub --&amp;amp;gt; (Promote to PyPI)
Automation --&amp;amp;gt; (Update Dependencies)
@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_シーケンス_条件付き公開&amp;quot;&amp;gt;シーケンス – 条件付き公開&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
!theme vibrant
left to right direction
Developer -&amp;amp;gt; GitHub: Push tag v1.2.3-rc
GitHub -&amp;amp;gt; CI: Run tests
CI -&amp;amp;gt; CD: Check release type
CD -&amp;amp;gt; Test PyPI: Publish RC
Developer -&amp;amp;gt; GitHub: Push tag v1.2.3
GitHub -&amp;amp;gt; CD: Publish to PyPI
CD -&amp;amp;gt; Docker Registry: Push Docker image
@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_ステータス_cicd_パイプライン&amp;quot;&amp;gt;ステータス – CI/CD パイプライン&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
[*] --&amp;amp;gt; Idle
Idle --&amp;amp;gt; CI_Running : push
CI_Running --&amp;amp;gt; CI_Success : tests ok
CI_Running --&amp;amp;gt; CI_Failed : tests fail
CI_Success --&amp;amp;gt; CD_Running : tag detected
CD_Running --&amp;amp;gt; CD_Success : publish ok
CD_Running --&amp;amp;gt; CD_Failed : error
CD_Success --&amp;amp;gt; [*]
@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_デプロイメント_cicdアーキテクチャ&amp;quot;&amp;gt;デプロイメント – CI/CDアーキテクチャ&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
node &amp;quot;開発者用マシン&amp;quot; {
  component &amp;quot;Git クライアント&amp;quot;
}

node &amp;quot;GitHub Actions&amp;quot; {
  component &amp;quot;CI ワークフロー&amp;quot;
  component &amp;quot;CD ワークフロー&amp;quot;
}

node &amp;quot;パッケージリポジトリ&amp;quot; {
  artifact &amp;quot;テスト PyPI&amp;quot;
  artifact &amp;quot;PyPI&amp;quot;
  artifact &amp;quot;Dockerレジストリ&amp;quot;
}

&amp;quot;開発者用マシン&amp;quot; --&amp;amp;gt; &amp;quot;GitHub Actions&amp;quot;
&amp;quot;GitHub Actions&amp;quot; --&amp;amp;gt; &amp;quot;テスト PyPI&amp;quot;
&amp;quot;GitHub Actions&amp;quot; --&amp;amp;gt; &amp;quot;PyPI&amp;quot;
&amp;quot;GitHub Actions&amp;quot; --&amp;amp;gt; &amp;quot;Dockerレジストリ&amp;quot;
@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_結論&amp;quot;&amp;gt;結論&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;この第三部では、次のことを見ました： - Poetryを使用してPythonパッケージングをモダン化する。 - Dockerを使用して再現可能なビルドを保証する。 - 条件付き公開を設定する。 依存関係の更新を自動化する。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;あなたは今ではCI/CDパイプラインを持っています&amp;lt;strong&amp;gt;完全、工業化され、安全&amp;lt;/strong&amp;gt;, あなたのプロジェクトとともに進化する準備ができています。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;</description>
        </item><item>
            <title>第2部: 高度なPython CI/CDパイプラインを工業化し、セキュリティを確保する</title>
            <link >https://cheroliv.com/blog/2025/0086_pypi_cicd_part_2_post.html</link>
            <pubDate>Fri, 18 Jul 2025 00:00:00 +0000</pubDate>
            <guid isPermaLink="false">blog/2025/0086_pypi_cicd_part_2_post.html</guid>
            <description>&amp;lt;div id=&amp;quot;toc&amp;quot; class=&amp;quot;toc&amp;quot;&amp;gt;
&amp;lt;div id=&amp;quot;toctitle&amp;quot;&amp;gt;Sommaire&amp;lt;/div&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel1&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_導入&amp;quot;&amp;gt;導入&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_cicdパイプラインのアーキテクチャ&amp;quot;&amp;gt;CI/CDパイプラインのアーキテクチャ&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_プロジェクトの構造&amp;quot;&amp;gt;プロジェクトの構造&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_pyproject_toml_を使用したパッケージの設定&amp;quot;&amp;gt;pyproject.toml を使用したパッケージの設定&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_cicdワークフロー_テストと品質&amp;quot;&amp;gt;CI/CDワークフロー - テストと品質&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_リリースとデプロイのワークフロー&amp;quot;&amp;gt;リリースとデプロイのワークフロー&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_アーキテクチャ図&amp;quot;&amp;gt;アーキテクチャ図&amp;lt;/a&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel2&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_シーケンス図_リリースプロセス&amp;quot;&amp;gt;シーケンス図 - リリースプロセス&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_状態図_パッケージのライフサイクル&amp;quot;&amp;gt;状態図 - パッケージのライフサイクル&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_デプロイメント図_cicdインフラストラクチャ&amp;quot;&amp;gt;デプロイメント図 - CI/CDインフラストラクチャ&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_パイプラインのオブジェクトとモデル&amp;quot;&amp;gt;パイプラインのオブジェクトとモデル&amp;lt;/a&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel2&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_クラス図_cicdテンプレート&amp;quot;&amp;gt;クラス図 - CI/CDテンプレート&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_シークレットの設定&amp;quot;&amp;gt;シークレットの設定&amp;lt;/a&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel2&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_github_actions_のシークレット&amp;quot;&amp;gt;GitHub Actions のシークレット&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_pypi_トークンの生成&amp;quot;&amp;gt;PyPI トークンの生成&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_ローカル開発スクリプト&amp;quot;&amp;gt;ローカル開発スクリプト&amp;lt;/a&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel2&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_メイクファイル&amp;quot;&amp;gt;メイクファイル&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_バージョン_スクリプト&amp;quot;&amp;gt;バージョン スクリプト&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_良い実践と推奨&amp;quot;&amp;gt;良い実践と推奨&amp;lt;/a&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel2&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_セマンティック_バージョニング&amp;quot;&amp;gt;セマンティック バージョニング&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_ブランチングの戦略&amp;quot;&amp;gt;ブランチングの戦略&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_テストとカバレッジ&amp;quot;&amp;gt;テストとカバレッジ&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_セキュリティ&amp;quot;&amp;gt;セキュリティ&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_監視と可観測性&amp;quot;&amp;gt;監視と可観測性&amp;lt;/a&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel2&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_パイプラインメトリクス&amp;quot;&amp;gt;パイプラインメトリクス&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_通知&amp;quot;&amp;gt;通知&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_結論&amp;quot;&amp;gt;結論&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_補足リソース&amp;quot;&amp;gt;補足リソース&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div id=&amp;quot;preamble&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;目的 : シンプルなパイプラインを、モダンなパッケージングおよびソフトウェアエンジニアリングの標準に適合した頑丈な産業用パイプラインに変換する。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_導入&amp;quot;&amp;gt;導入&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;このシリーズの第1部では、PythonパッケージをPyPIに公開するためのテストとリリースを自動化する、シンプルかつ効果的なCI/CDパイプラインを構築しました。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;今がこのパイプラインをプロフェッショナル化する時です。 この第二部では、以下のことを行います：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;現代の標準に移行する pyproject.toml,&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;品質およびセキュリティツールを追加する (Black, Mypy, Bandit, Safety),&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;マルチバージョンテストを設定する、&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;Test PyPI を使用して段階的なデプロイを統合する,&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;バージョニングを自動化し、パイプラインの監視を改善する。&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;機能的なパイプラインからプロフェッショナルなCI/CDインフラストラクチャへ移行する準備をしてください。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;PythonアプリケーションをPyPIにデプロイするには、テスト、ビルド、パッケージの公開を自動化する堅牢なCI/CDパイプラインが必要です。 この記事では、GitHub Actions を利用した Python CLI アプリケーション向けの完全なパイプラインの構築方法について詳しく説明し、現代の Python エコシステムのベストプラクティスに従います。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_cicdパイプラインのアーキテクチャ&amp;quot;&amp;gt;CI/CDパイプラインのアーキテクチャ&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;私たちが構築するパイプラインは、複数のステップからなるアプローチに従います：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
!theme plain
title Python用 CI/CD パイプライン (PyPI へ)
skinparam backgroundColor #f8f9fa
skinparam componentStyle rectangle

rectangle &amp;quot;開発者&amp;quot; as dev
rectangle &amp;quot;GitHub リポジトリ&amp;quot; as repo {
  rectangle &amp;quot;.github/workflows/&amp;quot; as workflows
  rectangle &amp;quot;tests/&amp;quot; as tests
  rectangle &amp;quot;setup.py / pyproject.toml&amp;quot; as setup
  rectangle &amp;quot;requirements.txt&amp;quot; as req
}

rectangle &amp;quot;ギットハブ アクションズ&amp;quot; as actions {
  rectangle &amp;quot;テストランナー&amp;quot; as test_runner
  rectangle &amp;quot;ビルド&amp;quot; as build
  rectangle &amp;quot;セキュリティスキャン&amp;quot; as security
  rectangle &amp;quot;品質チェック&amp;quot; as quality
}

rectangle &amp;quot;PyPI&amp;quot; as pypi {
  rectangle &amp;quot;テスト PyPI&amp;quot; as test_pypi
  rectangle &amp;quot;本番の PyPI&amp;quot; as prod_pypi
}

rectangle &amp;quot;ユーザー&amp;quot; as users

dev --&amp;amp;gt; repo : push/PR
repo --&amp;amp;gt; actions : trigger workflow
actions --&amp;amp;gt; test_runner : run tests
actions --&amp;amp;gt; security : security checks
actions --&amp;amp;gt; quality : code quality
actions --&amp;amp;gt; build : build package
build --&amp;amp;gt; test_pypi : deploy (pre-release)
build --&amp;amp;gt; prod_pypi : deploy (release)
prod_pypi --&amp;amp;gt; users : install package

@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_プロジェクトの構造&amp;quot;&amp;gt;プロジェクトの構造&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;配布に対応したPython CLIアプリケーションは、標準化された構造に従う必要があります：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-text hljs&amp;quot; data-lang=&amp;quot;text&amp;quot;&amp;gt;playlist-downloader/
├── .github/
│   └── workflows/
│       ├── ci.yml
│       ├── release.yml
│       └── security.yml
├── src/
│   └── playlist_downloader/
│       ├── __init__.py
│       ├── cli.py
│       ├── core/
│       └── adapters/
├── tests/
│   ├── unit/
│   ├── integration/
│   └── conftest.py
├── docs/
├── pyproject.toml
├── requirements.txt
├── requirements-dev.txt
├── MANIFEST.in
├── README.md
├── LICENSE
└── CHANGELOG.md&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_pyproject_toml_を使用したパッケージの設定&amp;quot;&amp;gt;pyproject.toml を使用したパッケージの設定&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;ファイル`pyproject.toml`は Python パッケージを設定するための現代の標準です :&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-toml hljs&amp;quot; data-lang=&amp;quot;toml&amp;quot;&amp;gt;[build-system]
requires = [&amp;quot;setuptools&amp;amp;gt;=45&amp;quot;, &amp;quot;wheel&amp;quot;, &amp;quot;setuptools_scm&amp;amp;gt;=6.2&amp;quot;]
build-backend = &amp;quot;setuptools.build_meta&amp;quot;

[project]
name = &amp;quot;playlist-downloader&amp;quot;
authors = [
    {name = &amp;quot;Christophe Hérolivier&amp;quot;, email = &amp;quot;cheroliv@example.com&amp;quot;},
]
description = &amp;quot;CLI tool for YouTube playlist management&amp;quot;
readme = &amp;quot;README.md&amp;quot;
requires-python = &amp;quot;&amp;amp;gt;=3.8&amp;quot;
keywords = [&amp;quot;youtube&amp;quot;, &amp;quot;playlist&amp;quot;, &amp;quot;cli&amp;quot;, &amp;quot;downloader&amp;quot;]
license = {text = &amp;quot;MIT&amp;quot;}
classifiers = [
    &amp;quot;Development Status :: 4 - Beta&amp;quot;,
    &amp;quot;Environment :: Console&amp;quot;,
    &amp;quot;Intended Audience :: End Users/Desktop&amp;quot;,
    &amp;quot;License :: OSI Approved :: MIT License&amp;quot;,
    &amp;quot;Operating System :: OS Independent&amp;quot;,
    &amp;quot;Programming Language :: Python :: 3&amp;quot;,
    &amp;quot;Programming Language :: Python :: 3.8&amp;quot;,
    &amp;quot;Programming Language :: Python :: 3.9&amp;quot;,
    &amp;quot;Programming Language :: Python :: 3.10&amp;quot;,
    &amp;quot;Programming Language :: Python :: 3.11&amp;quot;,
    &amp;quot;Topic :: Multimedia :: Sound/Audio&amp;quot;,
    &amp;quot;Topic :: Utilities&amp;quot;,
]
dependencies = [
    &amp;quot;typer&amp;amp;gt;=0.9.0&amp;quot;,
    &amp;quot;yt-dlp&amp;amp;gt;=2023.7.6&amp;quot;,
    &amp;quot;google-api-python-client&amp;amp;gt;=2.0.0&amp;quot;,
    &amp;quot;google-auth-oauthlib&amp;amp;gt;=1.0.0&amp;quot;,
    &amp;quot;pyyaml&amp;amp;gt;=6.0&amp;quot;,
    &amp;quot;rich&amp;amp;gt;=13.0.0&amp;quot;,
]
dynamic = [&amp;quot;version&amp;quot;]

[project.optional-dependencies]
dev = [
    &amp;quot;pytest&amp;amp;gt;=7.0.0&amp;quot;,
    &amp;quot;pytest-cov&amp;amp;gt;=4.0.0&amp;quot;,
    &amp;quot;pytest-mock&amp;amp;gt;=3.10.0&amp;quot;,
    &amp;quot;black&amp;amp;gt;=23.0.0&amp;quot;,
    &amp;quot;flake8&amp;amp;gt;=6.0.0&amp;quot;,
    &amp;quot;mypy&amp;amp;gt;=1.0.0&amp;quot;,
    &amp;quot;pre-commit&amp;amp;gt;=3.0.0&amp;quot;,
    &amp;quot;tox&amp;amp;gt;=4.0.0&amp;quot;,
]
test = [
    &amp;quot;pytest&amp;amp;gt;=7.0.0&amp;quot;,
    &amp;quot;pytest-cov&amp;amp;gt;=4.0.0&amp;quot;,
    &amp;quot;pytest-mock&amp;amp;gt;=3.10.0&amp;quot;,
]

[project.urls]
Homepage = &amp;quot;https://github.com/cheroliv/playlist-downloader&amp;quot;
Documentation = &amp;quot;https://github.com/cheroliv/playlist-downloader#readme&amp;quot;
Repository = &amp;quot;https://github.com/cheroliv/playlist-downloader.git&amp;quot;
&amp;quot;Bug Tracker&amp;quot; = &amp;quot;https://github.com/cheroliv/playlist-downloader/issues&amp;quot;

[project.scripts]
playlist-downloader = &amp;quot;playlist_downloader.cli:main&amp;quot;

[tool.setuptools_scm]
write_to = &amp;quot;src/playlist_downloader/_version.py&amp;quot;

[tool.setuptools.packages.find]
where = [&amp;quot;src&amp;quot;]

[tool.pytest.ini_options]
testpaths = [&amp;quot;tests&amp;quot;]
python_files = [&amp;quot;test_*.py&amp;quot;]
python_classes = [&amp;quot;Test*&amp;quot;]
python_functions = [&amp;quot;test_*&amp;quot;]
addopts = [
    &amp;quot;--cov=src/playlist_downloader&amp;quot;,
    &amp;quot;--cov-report=html&amp;quot;,
    &amp;quot;--cov-report=term-missing&amp;quot;,
    &amp;quot;--cov-fail-under=85&amp;quot;,
]

[tool.black]
line-length = 88
target-version = [&amp;#39;py38&amp;#39;]
include = &amp;#39;\.pyi?$&amp;#39;
extend-exclude = &amp;#39;&amp;#39;&amp;#39;
/(
  \.eggs
  | \.git
  | \.hg
  | \.mypy_cache
  | \.tox
  | \.venv
  | _build
  | buck-out
  | build
  | dist
)/
&amp;#39;&amp;#39;&amp;#39;

[tool.mypy]
python_version = &amp;quot;3.8&amp;quot;
warn_return_any = true
warn_unused_configs = true
disallow_untyped_defs = true
disallow_incomplete_defs = true
check_untyped_defs = true
disallow_untyped_decorators = true
no_implicit_optional = true
warn_redundant_casts = true
warn_unused_ignores = true
warn_no_return = true
warn_unreachable = true
strict_equality = true

[[tool.mypy.overrides]]
module = [
    &amp;quot;yt_dlp.*&amp;quot;,
    &amp;quot;googleapiclient.*&amp;quot;,
    &amp;quot;google_auth_oauthlib.*&amp;quot;,
]
ignore_missing_imports = true&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_cicdワークフロー_テストと品質&amp;quot;&amp;gt;CI/CDワークフロー - テストと品質&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;メインワークフロー (&amp;lt;code&amp;gt;ci.yml&amp;lt;/code&amp;gt;) Python の複数のバージョンでテストを実行します :&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-yaml hljs&amp;quot; data-lang=&amp;quot;yaml&amp;quot;&amp;gt;name: CI

on:
  push:
    branches: [ main, develop ]
  pull_request:
    branches: [ main ]

jobs:
  test:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        python-version: [&amp;quot;3.8&amp;quot;, &amp;quot;3.9&amp;quot;, &amp;quot;3.10&amp;quot;, &amp;quot;3.11&amp;quot;]

    steps:
    - uses: actions/checkout@v4
      with:
        fetch-depth: 0

    - name: Set up Python ${{ matrix.python-version }}
      uses: actions/setup-python@v4
      with:
        python-version: ${{ matrix.python-version }}

    - name: Cache dependencies
      uses: actions/cache@v3
      with:
        path: |
          ~/.cache/pip
          ~/.cache/pre-commit
        key: ${{ runner.os }}-pip-${{ hashFiles(&amp;#39;**/requirements*.txt&amp;#39;) }}
        restore-keys: |
          ${{ runner.os }}-pip-

    - name: Install dependencies
      run: |
        python -m pip install --upgrade pip
        pip install -e &amp;quot;.[dev]&amp;quot;

    - name: Lint with flake8
      run: |
        flake8 src tests --count --select=E9,F63,F7,F82 --show-source --statistics
        flake8 src tests --count --exit-zero --max-complexity=10 --max-line-length=88 --statistics

    - name: Check code formatting with Black
      run: black --check src tests

    - name: Type checking with mypy
      run: mypy src

    - name: Run tests with pytest
      run: |
        pytest tests/ -v --cov=src/playlist_downloader \
          --cov-report=xml --cov-report=term-missing

    - name: Upload coverage to Codecov
      uses: codecov/codecov-action@v3
      if: matrix.python-version == &amp;#39;3.11&amp;#39;
      with:
        file: ./coverage.xml
        flags: unittests
        name: codecov-umbrella

  security:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v4

    - name: Set up Python
      uses: actions/setup-python@v4
      with:
        python-version: &amp;quot;3.11&amp;quot;

    - name: Install dependencies
      run: |
        python -m pip install --upgrade pip
        pip install bandit[toml] safety

    - name: Run security checks with bandit
      run: bandit -r src/ -f json -o bandit-report.json

    - name: Check dependencies with safety
      run: safety check --json --output safety-report.json

    - name: Upload security reports
      uses: actions/upload-artifact@v3
      if: always()
      with:
        name: security-reports
        path: |
          bandit-report.json
          safety-report.json

  build:
    needs: [test, security]
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v4
      with:
        fetch-depth: 0

    - name: Set up Python
      uses: actions/setup-python@v4
      with:
        python-version: &amp;quot;3.11&amp;quot;

    - name: Install build dependencies
      run: |
        python -m pip install --upgrade pip
        pip install build twine

    - name: Build package
      run: python -m build

    - name: Check package with twine
      run: twine check dist/*

    - name: Upload build artifacts
      uses: actions/upload-artifact@v3
      with:
        name: dist
        path: dist/&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_リリースとデプロイのワークフロー&amp;quot;&amp;gt;リリースとデプロイのワークフロー&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;リリースワークフロー (&amp;lt;code&amp;gt;release.yml&amp;lt;/code&amp;gt;) PyPIへの自動公開を管理します :&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-yaml hljs&amp;quot; data-lang=&amp;quot;yaml&amp;quot;&amp;gt;name: Release

on:
  push:
    tags:
      - &amp;#39;v*.*.*&amp;#39;
  workflow_dispatch:
    inputs:
      environment:
        description: &amp;#39;Deployment environment&amp;#39;
        required: true
        default: &amp;#39;test&amp;#39;
        type: choice
        options:
        - test
        - production

env:
  PYTHON_VERSION: &amp;quot;3.11&amp;quot;

jobs:
  release:
    runs-on: ubuntu-latest
    environment:
      name: ${{ github.event.inputs.environment || (startsWith(github.ref, &amp;#39;refs/tags/&amp;#39;) &amp;amp;amp;&amp;amp;amp; &amp;#39;production&amp;#39; || &amp;#39;test&amp;#39;) }}

    steps:
    - uses: actions/checkout@v4
      with:
        fetch-depth: 0

    - name: Set up Python
      uses: actions/setup-python@v4
      with:
        python-version: ${{ env.PYTHON_VERSION }}

    - name: Install dependencies
      run: |
        python -m pip install --upgrade pip
        pip install build twine

    - name: Build package
      run: python -m build

    - name: Check package
      run: twine check dist/*

    - name: Publish to Test PyPI
      if: github.event.inputs.environment == &amp;#39;test&amp;#39; || (startsWith(github.ref, &amp;#39;refs/tags/&amp;#39;) &amp;amp;amp;&amp;amp;amp; contains(github.ref, &amp;#39;rc&amp;#39;))
      env:
        TWINE_USERNAME: __token__
        TWINE_PASSWORD: ${{ secrets.TEST_PYPI_API_TOKEN }}
      run: |
        twine upload --repository testpypi dist/*

    - name: Publish to PyPI
      if: github.event.inputs.environment == &amp;#39;production&amp;#39; || (startsWith(github.ref, &amp;#39;refs/tags/&amp;#39;) &amp;amp;amp;&amp;amp;amp; !contains(github.ref, &amp;#39;rc&amp;#39;))
      env:
        TWINE_USERNAME: __token__
        TWINE_PASSWORD: ${{ secrets.PYPI_API_TOKEN }}
      run: |
        twine upload dist/*

    - name: Create GitHub Release
      if: startsWith(github.ref, &amp;#39;refs/tags/&amp;#39;)
      uses: actions/create-release@v1
      env:
        GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
      with:
        tag_name: ${{ github.ref }}
        release_name: Release ${{ github.ref }}
        draft: false
        prerelease: ${{ contains(github.ref, &amp;#39;rc&amp;#39;) }}

  post-release:
    needs: release
    runs-on: ubuntu-latest
    if: startsWith(github.ref, &amp;#39;refs/tags/&amp;#39;)

    steps:
    - uses: actions/checkout@v4

    - name: Set up Python
      uses: actions/setup-python@v4
      with:
        python-version: ${{ env.PYTHON_VERSION }}

    - name: Test installation from PyPI
      run: |
        sleep 60  # Attendre la propagation sur PyPI
        pip install playlist-downloader
        playlist-downloader --version

    - name: Update documentation
      run: |
        # Script pour mettre à jour la documentation
        echo &amp;quot;Documentation updated for version ${GITHUB_REF#refs/tags/}&amp;quot;&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_アーキテクチャ図&amp;quot;&amp;gt;アーキテクチャ図&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_シーケンス図_リリースプロセス&amp;quot;&amp;gt;シーケンス図 - リリースプロセス&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
!theme plain
title PyPIへのリリースシーケンス
actor Developer as dev
participant &amp;quot;GitHub&amp;quot; as gh
participant &amp;quot;GitHub Actions&amp;quot; as ga
participant &amp;quot;テスト PyPI&amp;quot; as tpypi
participant &amp;quot;PyPI&amp;quot; as pypi
participant &amp;quot;ユーザー&amp;quot; as users

dev -&amp;amp;gt; gh : git push --tags v1.2.3
gh -&amp;amp;gt; ga : trigger release workflow

ga -&amp;amp;gt; ga : checkout code
ga -&amp;amp;gt; ga : setup Python environment
ga -&amp;amp;gt; ga : install dependencies
ga -&amp;amp;gt; ga : run tests
ga -&amp;amp;gt; ga : build package (wheel + sdist)
ga -&amp;amp;gt; ga : check package with twine

alt Pre-release (rc tag)
    ga -&amp;amp;gt; tpypi : upload to Test PyPI
    tpypi -&amp;amp;gt; ga : confirm upload
else Stable release
    ga -&amp;amp;gt; pypi : upload to PyPI
    pypi -&amp;amp;gt; ga : confirm upload
end

ga -&amp;amp;gt; gh : create GitHub release
ga -&amp;amp;gt; ga : test installation from PyPI

users -&amp;amp;gt; pypi : pip install playlist-downloader
pypi -&amp;amp;gt; users : download package

@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_状態図_パッケージのライフサイクル&amp;quot;&amp;gt;状態図 - パッケージのライフサイクル&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
!theme plain
title Pythonパッケージの状態
[*] --&amp;amp;gt; Development
Development --&amp;amp;gt; Testing : commit/PR
Testing --&amp;amp;gt; Development : tests fail
Testing --&amp;amp;gt; Built : tests pass
Built --&amp;amp;gt; TestPyPI : pre-release tag
Built --&amp;amp;gt; PyPI : stable tag
TestPyPI --&amp;amp;gt; PyPI : validation OK
PyPI --&amp;amp;gt; Published
Published --&amp;amp;gt; [*]

state Development {
  [*] --&amp;amp;gt; Coding
  Coding --&amp;amp;gt; LocalTesting
  LocalTesting --&amp;amp;gt; Coding : fix issues
  LocalTesting --&amp;amp;gt; ReadyForCI : all tests pass
}

state Testing {
  [*] --&amp;amp;gt; CITests
  CITests --&amp;amp;gt; SecurityScan
  SecurityScan --&amp;amp;gt; QualityCheck
  QualityCheck --&amp;amp;gt; BuildValidation
}

@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_デプロイメント図_cicdインフラストラクチャ&amp;quot;&amp;gt;デプロイメント図 - CI/CDインフラストラクチャ&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
!theme plain
title 導入インフラストラクチャ
node &amp;quot;ギットハブ&amp;quot; {
  component &amp;quot;リポジトリ&amp;quot; as repo
  component &amp;quot;アクション ランナー&amp;quot; as runner
  component &amp;quot;シークレットストア&amp;quot; as secrets
}

node &amp;quot;PyPI インフラストラクチャ&amp;quot; {
  component &amp;quot;PyPI&amp;quot; as pypi
  component &amp;quot;テスト PyPI&amp;quot; as testpypi
  database &amp;quot;パッケージインデックス&amp;quot; as index
}

node &amp;quot;開発者マシン&amp;quot; {
  component &amp;quot;Git クライアント&amp;quot; as git
  component &amp;quot;Python環境&amp;quot; as python
  component &amp;quot;統合開発環境&amp;quot; as ide
}

node &amp;quot;ユーザー環境&amp;quot; {
  component &amp;quot;ピップ&amp;quot; as pip_client
  component &amp;quot;Python ランタイム&amp;quot; as py_runtime
}

git --&amp;amp;gt; repo : push code/tags
repo --&amp;amp;gt; runner : trigger workflows
runner --&amp;amp;gt; secrets : read API tokens
runner --&amp;amp;gt; testpypi : upload pre-release
runner --&amp;amp;gt; pypi : upload release
pypi --&amp;amp;gt; index : store package
pip_client --&amp;amp;gt; pypi : download package
py_runtime &amp;amp;lt;-- pip_client : install package

@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_パイプラインのオブジェクトとモデル&amp;quot;&amp;gt;パイプラインのオブジェクトとモデル&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_クラス図_cicdテンプレート&amp;quot;&amp;gt;クラス図 - CI/CDテンプレート&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
!theme plain
title CI/CDパイプラインのモデル
class PipelineConfig {
  +python_versions: List[str]
  +test_environments: List[str]
  +security_checks: bool
  +coverage_threshold: float
  +validate()
}

class BuildArtifact {
  +name: str
  +version: str
  +wheel_path: str
  +sdist_path: str
  +checksums: Dict[str, str]
  +validate_integrity()
}

class TestResult {
  +test_suite: str
  +python_version: str
  +passed: int
  +failed: int
  +coverage: float
  +duration: float
  +is_success(): bool
}

class SecurityReport {
  +bandit_issues: List[Issue]
  +safety_vulnerabilities: List[Vulnerability]
  +severity_level: str
  +is_secure(): bool
}

class DeploymentTarget {
  +name: str
  +url: str
  +api_token: str
  +environment: str
  +deploy(artifact: BuildArtifact)
}

class ReleaseManager {
  +version: str
  +changelog: str
  +artifacts: List[BuildArtifact]
  +test_results: List[TestResult]
  +security_report: SecurityReport
  +deploy_to_test()
  +deploy_to_production()
  +create_github_release()
}

PipelineConfig ||--o{ TestResult
ReleaseManager *-- BuildArtifact
ReleaseManager *-- SecurityReport
ReleaseManager o-- DeploymentTarget
DeploymentTarget ..&amp;amp;gt; BuildArtifact : uses

@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_シークレットの設定&amp;quot;&amp;gt;シークレットの設定&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;パイプラインが機能するように、次のシークレットをGitHubで設定する必要があります：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_github_actions_のシークレット&amp;quot;&amp;gt;GitHub Actions のシークレット&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;# Dans Settings &amp;amp;gt; Secrets and variables &amp;amp;gt; Actions

# Token PyPI pour la production
PYPI_API_TOKEN=pypi-...

# Token Test PyPI pour les pré-releases
TEST_PYPI_API_TOKEN=pypi-...

# Token GitHub pour créer les releases
GITHUB_TOKEN=(automatiquement fourni)

# Token Codecov (optionnel)
CODECOV_TOKEN=...&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_pypi_トークンの生成&amp;quot;&amp;gt;PyPI トークンの生成&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;# 1. Créer un compte sur PyPI et Test PyPI
# 2. Aller dans Account Settings &amp;amp;gt; API tokens
# 3. Créer un token avec scope &amp;quot;Entire account&amp;quot; ou spécifique au projet
# 4. Format du token : pypi-AgEIcHlwaS5vcmc...&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_ローカル開発スクリプト&amp;quot;&amp;gt;ローカル開発スクリプト&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;開発を容易にするために、ユーティリティスクリプトを作成してください：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_メイクファイル&amp;quot;&amp;gt;メイクファイル&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-makefile hljs&amp;quot; data-lang=&amp;quot;makefile&amp;quot;&amp;gt;.PHONY: install test lint format security build clean release-test release-prod

install:
	pip install -e &amp;quot;.[dev]&amp;quot;

test:
	pytest tests/ -v --cov=src/playlist_downloader

lint:
	flake8 src tests
	mypy src

format:
	black src tests

security:
	bandit -r src/
	safety check

build:
	python -m build
	twine check dist/*

clean:
	rm -rf build/ dist/ *.egg-info/
	find . -type d -name __pycache__ -delete
	find . -name &amp;quot;*.pyc&amp;quot; -delete

release-test: clean build
	twine upload --repository testpypi dist/*

release-prod: clean build
	twine upload dist/*

pre-commit: format lint test security
	@echo &amp;quot;✅ Prêt pour commit&amp;quot;&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_バージョン_スクリプト&amp;quot;&amp;gt;バージョン スクリプト&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-python hljs&amp;quot; data-lang=&amp;quot;python&amp;quot;&amp;gt;#!/usr/bin/env python3
&amp;quot;&amp;quot;&amp;quot;Script pour gérer les versions du projet.&amp;quot;&amp;quot;&amp;quot;

import sys
import subprocess
from pathlib import Path

def get_current_version():
    &amp;quot;&amp;quot;&amp;quot;Récupère la version actuelle depuis git.&amp;quot;&amp;quot;&amp;quot;
    try:
        result = subprocess.run(
            [&amp;quot;git&amp;quot;, &amp;quot;describe&amp;quot;, &amp;quot;--tags&amp;quot;, &amp;quot;--abbrev=0&amp;quot;],
            capture_output=True,
            text=True,
            check=True
        )
        return result.stdout.strip()
    except subprocess.CalledProcessError:
        return &amp;quot;0.0.0&amp;quot;

def create_version_tag(version, message=None):
    &amp;quot;&amp;quot;&amp;quot;Crée un tag de version.&amp;quot;&amp;quot;&amp;quot;
    if not version.startswith(&amp;#39;v&amp;#39;):
        version = f&amp;#39;v{version}&amp;#39;

    tag_message = message or f&amp;quot;Release {version}&amp;quot;

    subprocess.run([&amp;quot;git&amp;quot;, &amp;quot;tag&amp;quot;, &amp;quot;-a&amp;quot;, version, &amp;quot;-m&amp;quot;, tag_message], check=True)
    print(f&amp;quot;✅ Tag {version} créé&amp;quot;)

    # Push le tag
    subprocess.run([&amp;quot;git&amp;quot;, &amp;quot;push&amp;quot;, &amp;quot;origin&amp;quot;, version], check=True)
    print(f&amp;quot;✅ Tag {version} poussé vers origin&amp;quot;)

if __name__ == &amp;quot;__main__&amp;quot;:
    if len(sys.argv) &amp;amp;lt; 2:
        current = get_current_version()
        print(f&amp;quot;Version actuelle: {current}&amp;quot;)
        print(&amp;quot;Usage: python version.py &amp;amp;lt;new_version&amp;amp;gt; [message]&amp;quot;)
        sys.exit(1)

    new_version = sys.argv[1]
    message = sys.argv[2] if len(sys.argv) &amp;amp;gt; 2 else None

    create_version_tag(new_version, message)&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_良い実践と推奨&amp;quot;&amp;gt;良い実践と推奨&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_セマンティック_バージョニング&amp;quot;&amp;gt;セマンティック バージョニング&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;セマンティック バージョニング (SemVer) を使用してください :&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;code&amp;gt;MAJOR.MINOR.PATCH&amp;lt;/code&amp;gt; (ex: 1.2.3)&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;code&amp;gt;MAJOR&amp;lt;/code&amp;gt;: 互換性のない変更&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;code&amp;gt;MINOR&amp;lt;/code&amp;gt;: 互換性のある新機能&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;code&amp;gt;PATCH&amp;lt;/code&amp;gt;: 互換性のあるバグ修正&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_ブランチングの戦略&amp;quot;&amp;gt;ブランチングの戦略&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-text hljs&amp;quot; data-lang=&amp;quot;text&amp;quot;&amp;gt;main          ──●──●──●──●──●────●── (releases stables)
               /       /          /
develop    ──●──●──●──●──●──●──●──●── (développement)
            /     /        /
feature/xxx  ●──●──●──●──●──/ (fonctionnalités)&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_テストとカバレッジ&amp;quot;&amp;gt;テストとカバレッジ&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;最小コードカバレッジ:85%&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;ビジネスロジックの単体テスト&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;アダプターの統合テスト&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;CLI用のエンドツーエンドテスト&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_セキュリティ&amp;quot;&amp;gt;セキュリティ&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;自動依存関係スキャン(Safety)&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;コードの静的解析 (Bandit)&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;コードに決して秘密を入れない&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;特定のPyPIトークンの使用&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_監視と可観測性&amp;quot;&amp;gt;監視と可観測性&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_パイプラインメトリクス&amp;quot;&amp;gt;パイプラインメトリクス&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-yaml hljs&amp;quot; data-lang=&amp;quot;yaml&amp;quot;&amp;gt;# .github/workflows/metrics.yml
name: Pipeline Metrics

on:
  workflow_run:
    workflows: [&amp;quot;CI&amp;quot;, &amp;quot;Release&amp;quot;]
    types: [completed]

jobs:
  metrics:
    runs-on: ubuntu-latest
    steps:
    - name: Collect metrics
      run: |
        echo &amp;quot;Pipeline: ${{ github.event.workflow_run.name }}&amp;quot;
        echo &amp;quot;Status: ${{ github.event.workflow_run.conclusion }}&amp;quot;
        echo &amp;quot;Duration: ${{ github.event.workflow_run.updated_at - github.event.workflow_run.created_at }}&amp;quot;
        # Envoyer vers système de monitoring&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_通知&amp;quot;&amp;gt;通知&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-yaml hljs&amp;quot; data-lang=&amp;quot;yaml&amp;quot;&amp;gt;# Ajout dans les workflows pour notifications
- name: Notify on failure
  if: failure()
  uses: 8398a7/action-slack@v3
  with:
    status: failure
    text: &amp;quot;❌ Pipeline failed for ${{ github.repository }}&amp;quot;
  env:
    SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK }}&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_結論&amp;quot;&amp;gt;結論&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;このPython用の完全なCI/CDパイプラインは、以下を提供します：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;完全自動化&amp;lt;/strong&amp;gt;コードの検証から出版まで&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;セキュリティ&amp;lt;/strong&amp;gt;: 自動スキャンおよび安全なシークレット管理&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;品質&amp;lt;/strong&amp;gt;: マルチバージョンテスト、リンティング、コードカバレッジ&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;信頼性&amp;lt;/strong&amp;gt;: Test PyPI を介した段階的なデプロイ&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;トレーサビリティ&amp;lt;/strong&amp;gt;: アーティファクト、レポート、および GitHub リリース&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;これらのベストプラクティスを採用することで、Python CLI アプリケーションに対して堅牢でプロフェッショナルなデリバリープロセスが保証され、長期的にプロジェクトのメンテナンスと進化が容易になります。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_補足リソース&amp;quot;&amp;gt;補足リソース&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;https://packaging.python.org/&amp;quot;&amp;gt;Python パッケージング ユーザーガイド&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;https://docs.github.com/en/actions&amp;quot;&amp;gt;GitHub Actionsドキュメント&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;https://pypi.org/help/&amp;quot;&amp;gt;PyPIヘルプドキュメント&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;https://semver.org/&amp;quot;&amp;gt;セマンティックバージョニング仕様&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;https://keepachangelog.com/&amp;quot;&amp;gt;変更ログを保持&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;</description>
        </item><item>
            <title>パート1 : PythonおよびPyPI用のシンプルなCI/CDパイプラインを設定する</title>
            <link >https://cheroliv.com/blog/2025/0085_pypi_cicd_part_1_post.html</link>
            <pubDate>Thu, 17 Jul 2025 00:00:00 +0000</pubDate>
            <guid isPermaLink="false">blog/2025/0085_pypi_cicd_part_1_post.html</guid>
            <description>&amp;lt;div id=&amp;quot;toc&amp;quot; class=&amp;quot;toc&amp;quot;&amp;gt;
&amp;lt;div id=&amp;quot;toctitle&amp;quot;&amp;gt;Sommaire&amp;lt;/div&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel1&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_イントロダクション&amp;quot;&amp;gt;イントロダクション&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_パイプラインのアーキテクチャ&amp;quot;&amp;gt;パイプラインのアーキテクチャ&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_継続的インテグレーション_ci_パイプラインの設定&amp;quot;&amp;gt;�継続的インテグレーション (CI) パイプラインの設定&amp;lt;/a&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel2&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_ciワークフローの構造&amp;quot;&amp;gt;CIワークフローの構造&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_ciステップの分析&amp;quot;&amp;gt;CIステップの分析&amp;lt;/a&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel3&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_トリガー_on&amp;quot;&amp;gt;トリガー (&amp;lt;code&amp;gt;on&amp;lt;/code&amp;gt;)&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_イントロダクション&amp;quot;&amp;gt;イントロダクション&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;目的： 読者が最小限かつ機能的な CI/CD パイプラインを構築できるように導き、Python アプリケーションに対して PyPI への自動デプロイを実現する。&amp;lt;/div&amp;gt;
&amp;lt;p&amp;gt;開発プロセスの自動化は、現代のプロジェクトにおいて必須となった。よく設計されたCI/CDパイプラインは、開発サイクルの早い段階で回帰を検出するだけでなく、デプロイメントプロセスを完全に自動化することも可能にする。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;この記事では、GitHub Actionsを使ってPythonアプリケーション用の完全なパイプラインをCI（継続的インテグレーション）からCD（継続的デプロイメント）まで設定する方法を探ります。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_パイプラインのアーキテクチャ&amp;quot;&amp;gt;パイプラインのアーキテクチャ&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;私たちのパイプラインは2つの異なるワークフローで構成されています：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;olist arabic&amp;quot;&amp;gt;
&amp;lt;ol class=&amp;quot;arabic&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;CIパイプライン&amp;lt;/strong&amp;gt;: 各プッシュおよびプルリクエストごとに実行されます&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;継続的デリバリーパイプライン&amp;lt;/strong&amp;gt;: GitHubのリリース時にのみトリガーされます&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ol&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
!theme plain

package &amp;quot;GitHub リポジトリ&amp;quot; {
  [Source Code] as source
  [GitHub Actions] as actions
}

package &amp;quot;CI パイプライン&amp;quot; {
  [Checkout] as checkout_ci
  [Setup Python] as python_ci
  [Install Dependencies] as deps_ci
  [Linting (Ruff)] as lint
  [Unit Tests] as tests
}

package &amp;quot;CD パイプライン&amp;quot; {
  [Checkout] as checkout_cd
  [Setup Python] as python_cd
  [Build Package] as build
  [Publish to PyPI] as pypi
}

source --&amp;amp;gt; actions : Push/PR
actions --&amp;amp;gt; checkout_ci
checkout_ci --&amp;amp;gt; python_ci
python_ci --&amp;amp;gt; deps_ci
deps_ci --&amp;amp;gt; lint
lint --&amp;amp;gt; tests

source --&amp;amp;gt; actions : Release
actions --&amp;amp;gt; checkout_cd : On Release
checkout_cd --&amp;amp;gt; python_cd
python_cd --&amp;amp;gt; build
build --&amp;amp;gt; pypi

@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_継続的インテグレーション_ci_パイプラインの設定&amp;quot;&amp;gt;�継続的インテグレーション (CI) パイプラインの設定&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_ciワークフローの構造&amp;quot;&amp;gt;CIワークフローの構造&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;CI ワークフローは、コードへの各貢献を検証するように設計されています。以下はその完全な設定です：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-yaml hljs&amp;quot; data-lang=&amp;quot;yaml&amp;quot;&amp;gt;name: CI/CD Pipeline

on:
  push:
    branches:
      - main
  pull_request:
    branches:
      - main

jobs:
  build:
    runs-on: ubuntu-latest

    steps:
    - name: Checkout code
      uses: actions/checkout@v4

    - name: Set up Python
      uses: actions/setup-python@v5
      with:
        python-version: &amp;#39;3.x&amp;#39;

    - name: Install dependencies
      run: |
        python -m pip install --upgrade pip
        pip install -r requirements.txt
        pip install ruff pytest pytest-mock

    - name: Run Linting (Ruff)
      run: ruff check .

    - name: Run Tests (Pytest)
      run: pytest&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_ciステップの分析&amp;quot;&amp;gt;CIステップの分析&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;sect3&amp;quot;&amp;gt;
&amp;lt;h4 id=&amp;quot;_トリガー_on&amp;quot;&amp;gt;トリガー (&amp;lt;code&amp;gt;on&amp;lt;/code&amp;gt;)&amp;lt;/h4&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-yaml hljs&amp;quot; data-lang=&amp;quot;yaml&amp;quot;&amp;gt;----
----
on:
  push:
    branches:
      - main
  pull_request:
    branches:
      - main
----

パイプラインは次の条件でトリガーされます : - 各プッシュをブランチに`main` - 各 pull request へ`main`

このアプローチは、メインコードが安定したまま保たれ、すべての貢献が統合前に検証されることを保証します。

==== 2. 実行環境

----

runs-on: ubuntu-latest

Ubuntu Latestは、性能、コスト、互換性の良いバランスを提供し、ほとんどのPythonプロジェクトに適しています。

==== 3. コードのチェックアウト

```yaml
----
----
- name: Checkout code
  uses: actions/checkout@v4
----

行動`checkout@v4`リポジトリのソースコードを取得します。バージョン v4 は、パフォーマンスとセキュリティの改善をもたらします。

==== 4. Python の設定

----

- name: Set up Python uses: actions/setup-python@v5 with: python-version: &amp;#39;3.x&amp;#39;

の使用`&amp;#39;3.x&amp;#39;`これにより、Python 3 の最新安定バージョンを自動的に使用できるようになり、メンテナンスが簡素化されます。

==== 5. 依存関係のインストール

```yaml
----
----
- name: Install dependencies
  run: |
    python -m pip install --upgrade pip
    pip install -r requirements.txt
    pip install ruff pytest pytest-mock
----

このステップ： - pipを最新バージョンに更新 - プロジェクトの依存関係をインストール - 開発ツール（リンティングとテスト）を追加

==== 6. Ruffによるリンティング

----

- name: Run Linting (Ruff) run: ruff check .

**ラフ**は非常に高速なRust製のPython linterです。Flake8、Black、isortなど複数のツールの機能を1つの高性能なツールに統合しています。

==== 7. テストの実行

```yaml
----
----
- name: Run Tests (Pytest)
  run: pytest
----

Pytest はテストスイート全体を実行し、変更が回帰を引き起こさないことを保証します。

== デプロイメントパイプライン (CD) の設定

=== CD ワークフローの構造

CD ワークフローは GitHub のリリース時にのみトリガーされ、PyPI への公開を自動化します :

[source,yaml]
----
name: Publish to PyPI

on:
  release:
    types:
      - published

jobs:
  deploy:
    runs-on: ubuntu-latest

    steps:
    - name: Checkout code
      uses: actions/checkout@v4

    - name: Set up Python
      uses: actions/setup-python@v5
      with:
        python-version: &amp;#39;3.x&amp;#39;

    - name: Install dependencies
      run: |
        python -m pip install --upgrade pip
        pip install setuptools wheel twine

    - name: Build and publish
      env:
        TWINE_USERNAME: __token__
        TWINE_PASSWORD: ${{ secrets.PYPI_API_TOKEN }}
      run: |
        python setup.py sdist bdist_wheel
        twine upload dist/*
----

=== CDステップの分析

==== リリース トリガー

----

on: release: types: - published

CDパイプラインはGitHubのリリースが公開されたときのみトリガーされます。このアプローチにより、デプロイメントの正確な制御が確保されます。

==== 2. ビルドツールのインストール

```yaml
----
----
pip install setuptools wheel twine
----

- **セットアップツール**: Python パッケージング ツール - **ホイール**: モダンなPythonディストリビューションフォーマット - **ひも**: セキュアなPyPIアップロードツール

==== 3. 認証設定

----

env: TWINE_USERNAME: __token__ TWINE_PASSWORD: ${{ secrets.PYPI_API_TOKEN }}

認証は、GitHubシークレットとして保存されたPyPI APIトークンを使用し、従来の認証情報よりも安全です。

==== 4. ビルドと公開

```yaml
----
----
run: |
  python setup.py sdist bdist_wheel
  twine upload dist/*
----

- `sdist`ソースディストリビューションを作成 - `bdist_wheel`: ホイールを作成 (バイナリディストリビューション) - `twine upload`: PyPIにディストリビューションを公開

== Pythonパッケージの設定

=== setup.pyの構造

パイプラインが機能するために、プロジェクトにはファイルを含めなければなりません`setup.py`:

[source,python]
----
from setuptools import setup, find_packages

with open(&amp;quot;README.adoc&amp;quot;, &amp;quot;r&amp;quot;, encoding=&amp;quot;utf-8&amp;quot;) as fh:
    long_description = fh.read()

setup(
    name=&amp;quot;playlist-downloader&amp;quot;,
    version=&amp;quot;1.0.0&amp;quot;,
    author=&amp;quot;Votre Nom&amp;quot;,
    author_email=&amp;quot;votre.email@example.com&amp;quot;,
    description=&amp;quot;CLI tool for managing YouTube playlists&amp;quot;,
    long_description=long_description,
    long_description_content_type=&amp;quot;text/plain&amp;quot;,
    url=&amp;quot;https://github.com/cheroliv/playlist-downloader&amp;quot;,
    packages=find_packages(),
    classifiers=[
        &amp;quot;Development Status :: 4 - Beta&amp;quot;,
        &amp;quot;Intended Audience :: Developers&amp;quot;,
        &amp;quot;License :: OSI Approved :: MIT License&amp;quot;,
        &amp;quot;Operating System :: OS Independent&amp;quot;,
        &amp;quot;Programming Language :: Python :: 3&amp;quot;,
        &amp;quot;Programming Language :: Python :: 3.8&amp;quot;,
        &amp;quot;Programming Language :: Python :: 3.9&amp;quot;,
        &amp;quot;Programming Language :: Python :: 3.10&amp;quot;,
        &amp;quot;Programming Language :: Python :: 3.11&amp;quot;,
    ],
    python_requires=&amp;quot;&amp;amp;gt;=3.8&amp;quot;,
    install_requires=[
        &amp;quot;typer&amp;amp;gt;=0.9.0&amp;quot;,
        &amp;quot;yt-dlp&amp;amp;gt;=2023.1.6&amp;quot;,
        &amp;quot;google-api-python-client&amp;amp;gt;=2.70.0&amp;quot;,
        &amp;quot;google-auth-oauthlib&amp;amp;gt;=0.7.1&amp;quot;,
        &amp;quot;pymonad&amp;amp;gt;=2.4.0&amp;quot;,
        &amp;quot;pyyaml&amp;amp;gt;=6.0&amp;quot;,
    ],
    entry_points={
        &amp;quot;console_scripts&amp;quot;: [
            &amp;quot;playlist-downloader=cli:app&amp;quot;,
        ],
    },
)
----

=== セットアップ.pyの重要なポイント

1. **メタデータ**: 名前, バージョン, 作者, 説明
2. **依存関係**必要なパッケージのリスト
3. **エントリーポイント**公開されたCLIコマンド
4. **分類器**PyPIのメタデータ

== GitHub Secretsを使用したセキュリティ

=== PyPIトークンの設定

1. **PyPIでAPIトークンを作成する**:

- PyPIにログインしてください - Account Settings &amp;amp;gt; API tokensに移動してください - 適切な権限で新しいトークンを作成してください

1. **GitHubにシークレットを追加**:

- リポジトリの設定 &amp;amp;gt; シークレットと変数 &amp;amp;gt; アクション - 新しいシークレットを作成`PYPI_API_TOKEN` - PyPIのトークンを貼り付けて

[plantuml, secrets-flow, svg]
----
@startuml
!theme plain

actor Developer as dev
participant &amp;quot;GitHubリポジトリ&amp;quot; as repo
participant &amp;quot;GitHub アクション&amp;quot; as actions
participant PyPI

dev -&amp;amp;gt; repo : Configure PYPI_API_TOKEN secret
repo -&amp;amp;gt; actions : Trigger CD pipeline on release
actions -&amp;amp;gt; actions : Access secret securely
actions -&amp;amp;gt; PyPI : Authenticate with token
PyPI -&amp;amp;gt; PyPI : Validate and publish package

note over actions, PyPI
  Token never exposed in logs
  Automatic rotation possible
end note

@enduml
----

== 完全なデプロイメントワークフロー

=== 展開シーケンス

[plantuml, deployment-sequence, svg]
----
@startuml
!theme plain

actor Developer as dev
participant &amp;quot;ローカルGit&amp;quot; as git
participant &amp;quot;GitHub&amp;quot; as github
participant &amp;quot;GitHub Actions&amp;quot; as actions
participant PyPI
participant &amp;quot;エンドユーザー&amp;quot; as users

dev -&amp;amp;gt; git : git tag v1.0.0
dev -&amp;amp;gt; git : git push origin v1.0.0
git -&amp;amp;gt; github : Push tag
dev -&amp;amp;gt; github : Create release from tag
github -&amp;amp;gt; actions : Trigger CD pipeline
actions -&amp;amp;gt; actions : Checkout code
actions -&amp;amp;gt; actions : Setup Python environment
actions -&amp;amp;gt; actions : Install build tools
actions -&amp;amp;gt; actions : Build distributions (sdist + wheel)
actions -&amp;amp;gt; PyPI : Upload to PyPI with token
PyPI -&amp;amp;gt; PyPI : Validate and publish
users -&amp;amp;gt; PyPI : pip install playlist-downloader

note over dev, github
  Release creation can be automated
  or done manually through GitHub UI
end note

@enduml
----

=== パイプラインの状態

[plantuml, pipeline-states, svg]
----
@startuml
!theme plain

[*] --&amp;amp;gt; Idle

Idle --&amp;amp;gt; CI_Running : Push/PR created
CI_Running --&amp;amp;gt; CI_Success : All checks pass
CI_Running --&amp;amp;gt; CI_Failed : Linting/Tests fail
CI_Success --&amp;amp;gt; Idle : Merge completed
CI_Failed --&amp;amp;gt; Idle : Fix and retry

Idle --&amp;amp;gt; CD_Running : Release published
CD_Running --&amp;amp;gt; CD_Success : Package published
CD_Running --&amp;amp;gt; CD_Failed : Build/Upload error
CD_Success --&amp;amp;gt; Idle : Package available on PyPI
CD_Failed --&amp;amp;gt; Idle : Fix and retry release

note on link #red : Blocks merge
note on link #green : Allows deployment

@enduml
----

== ベストプラクティスと最適化

=== バージョン管理

セマンティックなGitタグを使用してください：

----

git tag -a v1.2.3 -m &amp;quot;Release version 1.2.3&amp;quot; git push origin v1.2.3

=== 2. マトリックステスト

複数のPythonバージョンでテストするには：

```yaml
----
----
strategy:
  matrix:
    python-version: [3.8, 3.9, &amp;quot;3.10&amp;quot;, &amp;quot;3.11&amp;quot;]
----

=== 3. 依存関係のキャッシュ

キャッシュでビルドを高速化：

----

- name: Cache pip dependencies uses: actions/cache@v3 with: path: ~/.cache/pip key: ${{ runner.os }}-pip-${{ hashFiles(&amp;#39;**/requirements.txt&amp;#39;) }}

=== 4. デプロイメント環境

GitHub環境を使用して、制御されたデプロイを行ってください :

```yaml
----
----
jobs:
  deploy:
    environment: production
    runs-on: ubuntu-latest
----

== 使用例とアーキテクチャ

=== ユースケース図

[plantuml, use-cases, svg]
----
@startuml
!theme plain

left to right direction

actor &amp;quot;開発者&amp;quot; as dev
actor &amp;quot;GitHub Actions&amp;quot; as ga
actor &amp;quot;エンドユーザー&amp;quot; as user

package &amp;quot;CI/CDシステム&amp;quot; {
  usecase &amp;quot;リンティングを実行&amp;quot; as lint
  usecase &amp;quot;テストを実行&amp;quot; as test
  usecase &amp;quot;パッケージのビルド&amp;quot; as build
  usecase &amp;quot;PyPIに公開する&amp;quot; as publish
  usecase &amp;quot;リリースを作成&amp;quot; as release
}

dev --&amp;amp;gt; lint : Pushes code
dev --&amp;amp;gt; test : Pushes code
dev --&amp;amp;gt; release : Creates release
ga --&amp;amp;gt; build : On release trigger
ga --&amp;amp;gt; publish : After successful build
user --&amp;amp;gt; publish : Downloads package

lint .&amp;amp;gt; test : triggers
test .&amp;amp;gt; build : on success
build .&amp;amp;gt; publish : on success

@enduml
----

=== デプロイメントのアーキテクチャ

[plantuml, deployment-architecture, svg]
----
@startuml
!theme plain

cloud &amp;quot;GitHub&amp;quot; {
  [Source Repository]
  [GitHub Actions]
  [Secrets Store]
}

cloud &amp;quot;パイピーアイ&amp;quot; {
  [Package Registry]
  [Distribution Files]
}

node &amp;quot;CI/CD パイプライン&amp;quot; {
  [Linting]
  [Testing]
  [Building]
  [Publishing]
}

[Source Repository] --&amp;amp;gt; [GitHub Actions] : Triggers
[GitHub Actions] --&amp;amp;gt; [Linting]
[Linting] --&amp;amp;gt; [Testing]
[Testing] --&amp;amp;gt; [Building]
[Building] --&amp;amp;gt; [Publishing]
[Publishing] --&amp;amp;gt; [Package Registry] : Uploads
[Secrets Store] --&amp;amp;gt; [Publishing] : Provides token

note as N1
  Secure token-based
  authentication
end note

[Secrets Store] .. N1

@enduml
----

== 監視とデバッグ

=== ログとモニタリング

GitHub Actionsは各ステップの詳細なログを提供します。デバッグするには：

1. **ログを確認してください**各ステップの
2. **デバッグを有効に**に`ACTIONS_STEP_DEBUG`
3. **アーティファクトを使ってください**ビルドファイルを保存するために

----

- name: Upload build artifacts uses: actions/upload-artifact@v3 if: failure() with: name: build-logs path: build/

=== 通知

Slack or email notifications.

We could also do: &amp;quot;Slackまたはメールの通知を追加してください:&amp;quot; (colon). Provide only that.

&amp;amp;lt;/think&amp;amp;gt;

Slackまたはメールの通知を追加してください:

```yaml
----
----
- name: Notify on failure
  if: failure()
  uses: 8398a7/action-slack@v3
  with:
    status: ${{ job.status }}
    webhook_url: ${{ secrets.SLACK_WEBHOOK }}
----

== 結論

GitHub Actions を使って堅牢な CI/CD パイプラインを構築すると、開発体験が劇的に変わります。linting、テスト、デプロイを自動化することで、あなたは：

- **エラーを減らしてください**本番中 - **サイクルを加速して**開発の - **信頼を向上させてください**あなたのリリースの中で - **協力を促進してください**チームで

このパイプラインは、lint ツール、テスト フレームワーク、またはデプロイ先を調整することで、さまざまな種類の Python プロジェクトに適合させることができます。

これらのワークフローの設定における初期投資は、時間の節約とデプロイメント時の手動エラーの削減によってすぐに元が取れます。

== 補足リソース

- https://docs.github.com/en/actions[ギットハブ アクションズ ドキュメント] - https://packaging.python.org/[Pythonパッケージングガイド] - https://docs.pytest.org/[Pytestドキュメント] - https://docs.astral.sh/ruff/[Ruff ドキュメンテーション] - https://twine.readthedocs.io/[トワイン ドキュメンテーション]

�✅ パイプライン機能が達成されました！ これで、GitHub Actions から直接 PyPI に Python パッケージを公開し、テストを自動化できるシンプルな CI/CD パイプラインができました。

しかし、このパイプラインは意図的に最小限に抑えられています。まだ、プロフェッショナルな文脈で不可欠な一部の側面をカバーしていません。

Pythonのマルチバージョンテスト,

自動セキュリティ分析,

Test PyPIを介した段階的な導入,

パイプラインの監視とメトリクス,

バージョニングの自動化および現代のベストプラクティスの統合（pyproject.toml）。

次のセクションでは、レベルを上げます。基本的なパイプラインを本格的な産業レベルのデプロイメントチェーン、つまり堅牢で安全なものに変換する方法を学びます。これは本番環境のPythonプロジェクトに対応できる状態になります。
----&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;</description>
        </item><item>
            <title>音楽Discordボットの開発：機能的アーキテクチャとログ駆動開発</title>
            <link >https://cheroliv.com/blog/2025/0084_disco_bot_discord_python_post.html</link>
            <pubDate>Wed, 16 Jul 2025 00:00:00 +0000</pubDate>
            <guid isPermaLink="false">blog/2025/0084_disco_bot_discord_python_post.html</guid>
            <description>&amp;lt;div id=&amp;quot;toc&amp;quot; class=&amp;quot;toc&amp;quot;&amp;gt;
&amp;lt;div id=&amp;quot;toctitle&amp;quot;&amp;gt;Table of Contents&amp;lt;/div&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel1&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_導入&amp;quot;&amp;gt;導入&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_コンテキストと現在の課題&amp;quot;&amp;gt;コンテキストと現在の課題&amp;lt;/a&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel2&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_ミュジックapiの進化&amp;quot;&amp;gt;ミュジックAPIの進化&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_ログ駆動開発アプローチ&amp;quot;&amp;gt;ログ駆動開発アプローチ&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_概念アーキテクチャ&amp;quot;&amp;gt;概念アーキテクチャ&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_スタック技術と関数型パラダイム&amp;quot;&amp;gt;スタック技術と関数型パラダイム&amp;lt;/a&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel2&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_技術的選択&amp;quot;&amp;gt;技術的選択&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_適用された機能的原則&amp;quot;&amp;gt;適用された機能的原則&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_アジャイルメソドロジーとバックログ&amp;quot;&amp;gt;アジャイルメソドロジーとバックログ&amp;lt;/a&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel2&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_主要なエピック&amp;quot;&amp;gt;主要なエピック&amp;lt;/a&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel3&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_エピック1インフラストラクチャーボット_discord&amp;quot;&amp;gt;エピック1：インフラストラクチャーボット Discord&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_epic_2_spotify_統合&amp;quot;&amp;gt;Epic 2 : Spotify 統合&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_エピック3_youtube統合&amp;quot;&amp;gt;エピック3 : YouTube統合&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_epic_4_音楽機能&amp;quot;&amp;gt;Epic 4 : 音楽機能&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_詳細なユーザーストーリー&amp;quot;&amp;gt;詳細なユーザーストーリー&amp;lt;/a&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel3&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_us1_1_ボットの初期化&amp;quot;&amp;gt;US1.1 : ボットの初期化&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_us2_1_spotify_インテリジェント検索&amp;quot;&amp;gt;US2.1 : Spotify インテリジェント検索&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_us3_1_抽出_youtube_レジリエント&amp;quot;&amp;gt;US3.1 : 抽出 YouTube レジリエント&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_ログ駆動開発アプローチ_2&amp;quot;&amp;gt;ログ駆動開発アプローチ&amp;lt;/a&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel2&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_ロギング戦略&amp;quot;&amp;gt;ロギング戦略&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_ログの構造&amp;quot;&amp;gt;ログの構造&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_ログデザインの例&amp;quot;&amp;gt;ログデザインの例&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_pydanticを使用したバリデーションアーキテクチャ&amp;quot;&amp;gt;Pydanticを使用したバリデーションアーキテクチャ&amp;lt;/a&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel2&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_データモデル&amp;quot;&amp;gt;データモデル&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_機能的なエラー管理&amp;quot;&amp;gt;機能的なエラー管理&amp;lt;/a&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel2&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_モナドとエラーハンドリング&amp;quot;&amp;gt;モナドとエラーハンドリング&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_制限回避戦略&amp;quot;&amp;gt;制限回避戦略&amp;lt;/a&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel2&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_マルチソースアプローチ&amp;quot;&amp;gt;マルチソースアプローチ&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_反復的開発計画&amp;quot;&amp;gt;反復的開発計画&amp;lt;/a&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel2&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_スプリントプランニング&amp;quot;&amp;gt;スプリントプランニング&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_品質メトリクス&amp;quot;&amp;gt;品質メトリクス&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_デプロイメントとモニタリング&amp;quot;&amp;gt;デプロイメントとモニタリング&amp;lt;/a&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel2&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_本番アーキテクチャ&amp;quot;&amp;gt;本番アーキテクチャ&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_プロアクティブモニタリング&amp;quot;&amp;gt;プロアクティブモニタリング&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_結論と展望&amp;quot;&amp;gt;結論と展望&amp;lt;/a&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel2&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_次のステップ&amp;quot;&amp;gt;次のステップ&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_導入&amp;quot;&amp;gt;&amp;lt;a class=&amp;quot;anchor&amp;quot; href=&amp;quot;#_導入&amp;quot;&amp;gt;&amp;lt;/a&amp;gt;導入&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;SpotifyおよびYouTubeのAPIを組み込んだDiscordボットの開発は、特にこれらのプラットフォームの最近の制限や進化に直面する現代的な技術的課題を表しています。この記事は、…に基づく方法論的アプローチを紹介&amp;lt;strong&amp;gt;ログ駆動開発&amp;lt;/strong&amp;gt;(LDD)は、テスト駆動開発の拡張で、Pythonを使った関数型パラダイムに適用された。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;私たちの目標：堅牢で保守性が高く拡張可能なボットを作成し、現在の音楽APIの制約を乗り越えながら、Discord上でシームレスなユーザー体験を提供すること。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_コンテキストと現在の課題&amp;quot;&amp;gt;&amp;lt;a class=&amp;quot;anchor&amp;quot; href=&amp;quot;#_コンテキストと現在の課題&amp;quot;&amp;gt;&amp;lt;/a&amp;gt;コンテキストと現在の課題&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_ミュジックapiの進化&amp;quot;&amp;gt;&amp;lt;a class=&amp;quot;anchor&amp;quot; href=&amp;quot;#_ミュジックapiの進化&amp;quot;&amp;gt;&amp;lt;/a&amp;gt;ミュジックAPIの進化&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;音楽プラットフォームは、アクセスポリシーを大幅に厳しくした：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;スポティファイ&amp;lt;/strong&amp;gt;制限: メタデータへのアクセス制限、割り当ての制限&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;ユーチューブ&amp;lt;/strong&amp;gt;強化されたアンチボット方針、認証の複雑化&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;ディスコード&amp;lt;/strong&amp;gt;: 新しいセキュリティとパフォーマンスの要件&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_ログ駆動開発アプローチ&amp;quot;&amp;gt;&amp;lt;a class=&amp;quot;anchor&amp;quot; href=&amp;quot;#_ログ駆動開発アプローチ&amp;quot;&amp;gt;&amp;lt;/a&amp;gt;ログ駆動開発アプローチ&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;LDDは、ログを開発の中心に置くことでTDDを拡張します:&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;olist arabic&amp;quot;&amp;gt;
&amp;lt;ol class=&amp;quot;arabic&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;ログの定義&amp;lt;/strong&amp;gt;実装の前に&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;観察による検証&amp;lt;/strong&amp;gt;期待される振る舞い&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;完全トレーサビリティ&amp;lt;/strong&amp;gt;データフロー&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;前向きなデバッグ&amp;lt;/strong&amp;gt;エラーを予測して&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ol&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_概念アーキテクチャ&amp;quot;&amp;gt;&amp;lt;a class=&amp;quot;anchor&amp;quot; href=&amp;quot;#_概念アーキテクチャ&amp;quot;&amp;gt;&amp;lt;/a&amp;gt;概念アーキテクチャ&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
!theme aws-orange

package &amp;quot;Discord Bot コア&amp;quot; {
  [Command Handler] as CH
  [Event Listener] as EL
  [Log Manager] as LM
}

package &amp;quot;音楽統合レイヤー&amp;quot; {
  [Spotify Client] as SC
  [YouTube Client] as YC
  [Audio Processor] as AP
}

package &amp;quot;機能コア&amp;quot; {
  [Data Validation] as DV
  [Business Logic] as BL
  [Error Handling] as EH
}

package &amp;quot;外部 API&amp;quot; {
  [Spotify API] as SAPI
  [YouTube API] as YAPI
  [Discord API] as DAPI
}

CH --&amp;amp;gt; BL
EL --&amp;amp;gt; BL
BL --&amp;amp;gt; DV
BL --&amp;amp;gt; EH
BL --&amp;amp;gt; LM

SC --&amp;amp;gt; SAPI
YC --&amp;amp;gt; YAPI
CH --&amp;amp;gt; DAPI

DV ..&amp;amp;gt; SC : validates
DV ..&amp;amp;gt; YC : validates
AP --&amp;amp;gt; SC
AP --&amp;amp;gt; YC

LM --&amp;amp;gt; EH : logs errors
LM --&amp;amp;gt; BL : logs operations

@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_スタック技術と関数型パラダイム&amp;quot;&amp;gt;&amp;lt;a class=&amp;quot;anchor&amp;quot; href=&amp;quot;#_スタック技術と関数型パラダイム&amp;quot;&amp;gt;&amp;lt;/a&amp;gt;スタック技術と関数型パラダイム&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_技術的選択&amp;quot;&amp;gt;&amp;lt;a class=&amp;quot;anchor&amp;quot; href=&amp;quot;#_技術的選択&amp;quot;&amp;gt;&amp;lt;/a&amp;gt;技術的選択&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;私たちのスタックは関数型プログラミングを中心に構成されています：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;dlist&amp;quot;&amp;gt;
&amp;lt;dl&amp;gt;
&amp;lt;dt class=&amp;quot;hdlist1&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;PyMonade&amp;lt;/strong&amp;gt;&amp;lt;/dt&amp;gt;
&amp;lt;dd&amp;gt;
&amp;lt;p&amp;gt;副作用の管理と関数の合成&amp;lt;/p&amp;gt;
&amp;lt;/dd&amp;gt;
&amp;lt;dt class=&amp;quot;hdlist1&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;ピダンティック&amp;lt;/strong&amp;gt;&amp;lt;/dt&amp;gt;
&amp;lt;dd&amp;gt;
&amp;lt;p&amp;gt;型安全なデータのバリデーションとシリアライズ&amp;lt;/p&amp;gt;
&amp;lt;/dd&amp;gt;
&amp;lt;dt class=&amp;quot;hdlist1&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;Asyncio&amp;lt;/strong&amp;gt;&amp;lt;/dt&amp;gt;
&amp;lt;dd&amp;gt;
&amp;lt;p&amp;gt;APIs向けの非同期プログラミング&amp;lt;/p&amp;gt;
&amp;lt;/dd&amp;gt;
&amp;lt;dt class=&amp;quot;hdlist1&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;ストラクトログ&amp;lt;/strong&amp;gt;&amp;lt;/dt&amp;gt;
&amp;lt;dd&amp;gt;
&amp;lt;p&amp;gt;LDD向けの構造化ログ&amp;lt;/p&amp;gt;
&amp;lt;/dd&amp;gt;
&amp;lt;/dl&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_適用された機能的原則&amp;quot;&amp;gt;&amp;lt;a class=&amp;quot;anchor&amp;quot; href=&amp;quot;#_適用された機能的原則&amp;quot;&amp;gt;&amp;lt;/a&amp;gt;適用された機能的原則&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
!theme plain

title 機能的データフロー
participant &amp;quot;Discord コマンド&amp;quot; as DC
participant &amp;quot;バリデーター&amp;quot; as V
participant &amp;quot;ビジネスロジック&amp;quot; as BL
participant &amp;quot;APIクライアント&amp;quot; as AC
participant &amp;quot;ロガー&amp;quot; as L

DC -&amp;amp;gt; V: Raw Input
activate V
V -&amp;amp;gt; V: Pydantic Validation
V -&amp;amp;gt; L: Log Validation
V --&amp;amp;gt; DC: Maybe[ValidData]
deactivate V

DC -&amp;amp;gt; BL: ValidData
activate BL
BL -&amp;amp;gt; BL: Pure Computation
BL -&amp;amp;gt; L: Log Business Logic
BL -&amp;amp;gt; AC: API Request
activate AC
AC -&amp;amp;gt; AC: IO Operation
AC -&amp;amp;gt; L: Log API Call
AC --&amp;amp;gt; BL: Maybe[Result]
deactivate AC
BL --&amp;amp;gt; DC: Either[Error, Success]
deactivate BL

DC -&amp;amp;gt; L: Log Final Result

@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_アジャイルメソドロジーとバックログ&amp;quot;&amp;gt;&amp;lt;a class=&amp;quot;anchor&amp;quot; href=&amp;quot;#_アジャイルメソドロジーとバックログ&amp;quot;&amp;gt;&amp;lt;/a&amp;gt;アジャイルメソドロジーとバックログ&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_主要なエピック&amp;quot;&amp;gt;&amp;lt;a class=&amp;quot;anchor&amp;quot; href=&amp;quot;#_主要なエピック&amp;quot;&amp;gt;&amp;lt;/a&amp;gt;主要なエピック&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;私たちの開発は4つの主要なエピックを中心に組織されています：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect3&amp;quot;&amp;gt;
&amp;lt;h4 id=&amp;quot;_エピック1インフラストラクチャーボット_discord&amp;quot;&amp;gt;&amp;lt;a class=&amp;quot;anchor&amp;quot; href=&amp;quot;#_エピック1インフラストラクチャーボット_discord&amp;quot;&amp;gt;&amp;lt;/a&amp;gt;エピック1：インフラストラクチャーボット Discord&amp;lt;/h4&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;ビジネスバリュー&amp;lt;/strong&amp;gt; : 堅牢で拡張可能な基盤&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;受入基準&amp;lt;/strong&amp;gt; : - 安定したDiscord接続と再接続の管理 モジュラーコマンドシステム - 統合された構造化ロギング 一元的なエラー処理&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect3&amp;quot;&amp;gt;
&amp;lt;h4 id=&amp;quot;_epic_2_spotify_統合&amp;quot;&amp;gt;&amp;lt;a class=&amp;quot;anchor&amp;quot; href=&amp;quot;#_epic_2_spotify_統合&amp;quot;&amp;gt;&amp;lt;/a&amp;gt;Epic 2 : Spotify 統合&amp;lt;/h4&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;業務価値&amp;lt;/strong&amp;gt; : 音楽メタデータへのアクセス&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;受け入れ基準 - セキュアな OAuth2 認証 - インテリジェントなキャッシュを使用したトラック検索 APIクォータ管理 - ネットワークエラー時のフォールバック&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect3&amp;quot;&amp;gt;
&amp;lt;h4 id=&amp;quot;_エピック3_youtube統合&amp;quot;&amp;gt;&amp;lt;a class=&amp;quot;anchor&amp;quot; href=&amp;quot;#_エピック3_youtube統合&amp;quot;&amp;gt;&amp;lt;/a&amp;gt;エピック3 : YouTube統合&amp;lt;/h4&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;ビジネス価値&amp;lt;/strong&amp;gt; : 音声コンテンツへのアクセス&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;受け入れ基準 - 制限の合法的な回避 - 音声抽出の最適化 - プライベート/削除されたビデオの管理 - YouTubeの利用規約を遵守する&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect3&amp;quot;&amp;gt;
&amp;lt;h4 id=&amp;quot;_epic_4_音楽機能&amp;quot;&amp;gt;&amp;lt;a class=&amp;quot;anchor&amp;quot; href=&amp;quot;#_epic_4_音楽機能&amp;quot;&amp;gt;&amp;lt;/a&amp;gt;Epic 4 : 音楽機能&amp;lt;/h4&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;ビジネスバリュー&amp;lt;/strong&amp;gt; : 完全なユーザーエクスペリエンス&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;受入基準&amp;lt;/strong&amp;gt; : - 高品質のオーディオ講義 インテリジェントな再生キュー - Discordの音声コマンド - クロスプラットフォーム同期&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_詳細なユーザーストーリー&amp;quot;&amp;gt;&amp;lt;a class=&amp;quot;anchor&amp;quot; href=&amp;quot;#_詳細なユーザーストーリー&amp;quot;&amp;gt;&amp;lt;/a&amp;gt;詳細なユーザーストーリー&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;sect3&amp;quot;&amp;gt;
&amp;lt;h4 id=&amp;quot;_us1_1_ボットの初期化&amp;quot;&amp;gt;&amp;lt;a class=&amp;quot;anchor&amp;quot; href=&amp;quot;#_us1_1_ボットの初期化&amp;quot;&amp;gt;&amp;lt;/a&amp;gt;US1.1 : ボットの初期化&amp;lt;/h4&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;として 私は確実に接続するDiscordボットが欲しい &amp;lt;strong&amp;gt;Afin de&amp;lt;/strong&amp;gt; サービスの可用性を確保する&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;DoD (完了の定義)&amp;lt;/strong&amp;gt; : - [ ] Botは起動時に自動的に接続します - [ ] 構造化ログは各ステップを文書化します 切断時の自動再接続 - [ ] 統合テストがパスする&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect3&amp;quot;&amp;gt;
&amp;lt;h4 id=&amp;quot;_us2_1_spotify_インテリジェント検索&amp;quot;&amp;gt;&amp;lt;a class=&amp;quot;anchor&amp;quot; href=&amp;quot;#_us2_1_spotify_インテリジェント検索&amp;quot;&amp;gt;&amp;lt;/a&amp;gt;US2.1 : Spotify インテリジェント検索&amp;lt;/h4&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;Discordユーザー[&amp;lt;strong&amp;gt;として&amp;lt;/strong&amp;gt;] &amp;lt;strong&amp;gt;私は&amp;lt;/strong&amp;gt; Spotify を使って曲を検索したい 音楽を発見し共有するために&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;国防総省&amp;lt;/strong&amp;gt; : - [ ] 注文`/search`機能的 - [ ] メタデータを含む関連する結果 - [ ] リクエストを最適化するローカルキャッシュ APIエラーを優雅に処理&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect3&amp;quot;&amp;gt;
&amp;lt;h4 id=&amp;quot;_us3_1_抽出_youtube_レジリエント&amp;quot;&amp;gt;&amp;lt;a class=&amp;quot;anchor&amp;quot; href=&amp;quot;#_us3_1_抽出_youtube_レジリエント&amp;quot;&amp;gt;&amp;lt;/a&amp;gt;US3.1 : 抽出 YouTube レジリエント&amp;lt;/h4&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;システムとして &amp;lt;strong&amp;gt;私は&amp;lt;/strong&amp;gt; YouTubeの音声を確実に抽出する サービスの継続性を維持するために&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;DoD&amp;lt;/strong&amp;gt; : - [ ] ToSを違反しない抽出 - [ ] 最適な音質 - [ ] 地理的制限の管理 - [ ] 詳細な操作ログ&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_ログ駆動開発アプローチ_2&amp;quot;&amp;gt;&amp;lt;a class=&amp;quot;anchor&amp;quot; href=&amp;quot;#_ログ駆動開発アプローチ_2&amp;quot;&amp;gt;&amp;lt;/a&amp;gt;ログ駆動開発アプローチ&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_ロギング戦略&amp;quot;&amp;gt;&amp;lt;a class=&amp;quot;anchor&amp;quot; href=&amp;quot;#_ロギング戦略&amp;quot;&amp;gt;&amp;lt;/a&amp;gt;ロギング戦略&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
!theme spacelab

title ログ駆動開発フロー
start

:Define Expected Behavior;
note right: Spécification des logs attendus

:Write Log Assertions;
note right: Tests basés sur les logs

:Implement Minimal Code;
note right: Code juste suffisant

:Run &amp;amp;amp; Observe Logs;
note right: Validation comportementale

if (Logs Match Expectations?) then (yes)
  :Refactor &amp;amp;amp; Optimize;
  note right: Amélioration continue
else (no)
  :Debug via Logs;
  note right: Analyse des écarts
  :Fix Implementation;
endif

:Integration Tests;
note right: Validation end-to-end

stop

@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_ログの構造&amp;quot;&amp;gt;&amp;lt;a class=&amp;quot;anchor&amp;quot; href=&amp;quot;#_ログの構造&amp;quot;&amp;gt;&amp;lt;/a&amp;gt;ログの構造&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;私たちのLDDアプローチは、セマンティックレベルを持つ構造化ログを使用します:&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;dlist&amp;quot;&amp;gt;
&amp;lt;dl&amp;gt;
&amp;lt;dt class=&amp;quot;hdlist1&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;�痕跡&amp;lt;/strong&amp;gt;&amp;lt;/dt&amp;gt;
&amp;lt;dd&amp;gt;
&amp;lt;p&amp;gt;詳細なデータフロー&amp;lt;/p&amp;gt;
&amp;lt;/dd&amp;gt;
&amp;lt;dt class=&amp;quot;hdlist1&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;デバッグ&amp;lt;/strong&amp;gt;&amp;lt;/dt&amp;gt;
&amp;lt;dd&amp;gt;
&amp;lt;p&amp;gt;関数の内部状態&amp;lt;/p&amp;gt;
&amp;lt;/dd&amp;gt;
&amp;lt;dt class=&amp;quot;hdlist1&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;情報&amp;lt;/strong&amp;gt;&amp;lt;/dt&amp;gt;
&amp;lt;dd&amp;gt;
&amp;lt;p&amp;gt;成功したビジネスオペレーション&amp;lt;/p&amp;gt;
&amp;lt;/dd&amp;gt;
&amp;lt;dt class=&amp;quot;hdlist1&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;WARN&amp;lt;/strong&amp;gt;&amp;lt;/dt&amp;gt;
&amp;lt;dd&amp;gt;
&amp;lt;p&amp;gt;劣化しているが管理されている状況&amp;lt;/p&amp;gt;
&amp;lt;/dd&amp;gt;
&amp;lt;dt class=&amp;quot;hdlist1&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;エラー&amp;lt;/strong&amp;gt;&amp;lt;/dt&amp;gt;
&amp;lt;dd&amp;gt;
&amp;lt;p&amp;gt;介入を必要とするエラー&amp;lt;/p&amp;gt;
&amp;lt;/dd&amp;gt;
&amp;lt;dt class=&amp;quot;hdlist1&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;CRITICAL&amp;lt;/strong&amp;gt;&amp;lt;/dt&amp;gt;
&amp;lt;dd&amp;gt;
&amp;lt;p&amp;gt;システム障害&amp;lt;/p&amp;gt;
&amp;lt;/dd&amp;gt;
&amp;lt;/dl&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_ログデザインの例&amp;quot;&amp;gt;&amp;lt;a class=&amp;quot;anchor&amp;quot; href=&amp;quot;#_ログデザインの例&amp;quot;&amp;gt;&amp;lt;/a&amp;gt;ログデザインの例&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;Spotifyの検索機能を実装する前に、そのログを定義します：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-none hljs&amp;quot;&amp;gt;INFO: spotify.search.start query=&amp;quot;bohemian rhapsody&amp;quot; user_id=123456
DEBUG: spotify.search.validation query_length=16 safe_chars=true
DEBUG: spotify.search.api_call endpoint=&amp;quot;/search&amp;quot; params={...}
INFO: spotify.search.success results_count=15 duration_ms=340&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_pydanticを使用したバリデーションアーキテクチャ&amp;quot;&amp;gt;&amp;lt;a class=&amp;quot;anchor&amp;quot; href=&amp;quot;#_pydanticを使用したバリデーションアーキテクチャ&amp;quot;&amp;gt;&amp;lt;/a&amp;gt;Pydanticを使用したバリデーションアーキテクチャ&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_データモデル&amp;quot;&amp;gt;&amp;lt;a class=&amp;quot;anchor&amp;quot; href=&amp;quot;#_データモデル&amp;quot;&amp;gt;&amp;lt;/a&amp;gt;データモデル&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;機能的なアプローチは、上流でのバリデーションを優先します：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
!theme cerulean-outline

class SpotifyTrack {
  +id: str
  +name: str
  +artists: List[str]
  +duration_ms: int
  +external_urls: Dict[str, str]
  --
  +validate_duration() : bool
  +to_discord_embed() : Embed
}

class YouTubeVideo {
  +id: str
  +title: str
  +duration: timedelta
  +available: bool
  --
  +validate_availability() : bool
  +extract_audio_url() : Optional[str]
}

class DiscordCommand {
  +command: str
  +args: List[str]
  +user: User
  +channel: Channel
  --
  +validate_permissions() : bool
  +log_execution() : None
}

SpotifyTrack --|&amp;amp;gt; BaseModel
YouTubeVideo --|&amp;amp;gt; BaseModel
DiscordCommand --|&amp;amp;gt; BaseModel

@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_機能的なエラー管理&amp;quot;&amp;gt;&amp;lt;a class=&amp;quot;anchor&amp;quot; href=&amp;quot;#_機能的なエラー管理&amp;quot;&amp;gt;&amp;lt;/a&amp;gt;機能的なエラー管理&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_モナドとエラーハンドリング&amp;quot;&amp;gt;&amp;lt;a class=&amp;quot;anchor&amp;quot; href=&amp;quot;#_モナドとエラーハンドリング&amp;quot;&amp;gt;&amp;lt;/a&amp;gt;モナドとエラーハンドリング&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;PyMonadeを使用すると、エラーのエレガントな処理が可能になります：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
!theme toy

title エラー処理フロー
participant &amp;quot;コマンド&amp;quot; as C
participant &amp;quot;もしもしもモナド&amp;quot; as M
participant &amp;quot;イーザーモナド&amp;quot; as E
participant &amp;quot;ロガー&amp;quot; as L

C -&amp;amp;gt; M: search_query
activate M

alt Valid Query
  M -&amp;amp;gt; E: Success(query)
  activate E
  E -&amp;amp;gt; E: api_call()

  alt API Success
    E -&amp;amp;gt; L: log_success()
    E --&amp;amp;gt; C: Right(result)
  else API Error
    E -&amp;amp;gt; L: log_api_error()
    E --&amp;amp;gt; C: Left(api_error)
  end
  deactivate E

else Invalid Query
  M -&amp;amp;gt; L: log_validation_error()
  M --&amp;amp;gt; C: Nothing
end

deactivate M

@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_制限回避戦略&amp;quot;&amp;gt;&amp;lt;a class=&amp;quot;anchor&amp;quot; href=&amp;quot;#_制限回避戦略&amp;quot;&amp;gt;&amp;lt;/a&amp;gt;制限回避戦略&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_マルチソースアプローチ&amp;quot;&amp;gt;&amp;lt;a class=&amp;quot;anchor&amp;quot; href=&amp;quot;#_マルチソースアプローチ&amp;quot;&amp;gt;&amp;lt;/a&amp;gt;マルチソースアプローチ&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;API の制限に直面して、私たちは多様化戦略を採用します：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
!theme mars

title マルチソース戦略
start

:User Request;

:Primary Source\n(Spotify);

if (Available?) then (yes)
  :Return Spotify Data;
  stop
else (no)
  :Log Fallback;
  :Secondary Source\n(YouTube Music);

  if (Available?) then (yes)
    :Return YouTube Data;
    stop
  else (no)
    :Tertiary Source\n(Local Cache);

    if (Available?) then (yes)
      :Return Cached Data;
      :Log Cache Hit;
      stop
    else (no)
      :Return Error;
      :Log Complete Failure;
      stop
    end
  end
end

@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_反復的開発計画&amp;quot;&amp;gt;&amp;lt;a class=&amp;quot;anchor&amp;quot; href=&amp;quot;#_反復的開発計画&amp;quot;&amp;gt;&amp;lt;/a&amp;gt;反復的開発計画&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_スプリントプランニング&amp;quot;&amp;gt;&amp;lt;a class=&amp;quot;anchor&amp;quot; href=&amp;quot;#_スプリントプランニング&amp;quot;&amp;gt;&amp;lt;/a&amp;gt;スプリントプランニング&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;私たちの開発は、2週間スプリントのサイクルに従っています：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;dlist&amp;quot;&amp;gt;
&amp;lt;dl&amp;gt;
&amp;lt;dt class=&amp;quot;hdlist1&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;スプリント 1-2&amp;lt;/strong&amp;gt;&amp;lt;/dt&amp;gt;
&amp;lt;dd&amp;gt;
&amp;lt;p&amp;gt;インフラストラクチャとDiscord Bot Core&amp;lt;/p&amp;gt;
&amp;lt;/dd&amp;gt;
&amp;lt;dt class=&amp;quot;hdlist1&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;スプリント 3-4&amp;lt;/strong&amp;gt;&amp;lt;/dt&amp;gt;
&amp;lt;dd&amp;gt;
&amp;lt;p&amp;gt;SpotifyとLDDの連携&amp;lt;/p&amp;gt;
&amp;lt;/dd&amp;gt;
&amp;lt;dt class=&amp;quot;hdlist1&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;スプリント 5-6&amp;lt;/strong&amp;gt;&amp;lt;/dt&amp;gt;
&amp;lt;dd&amp;gt;
&amp;lt;p&amp;gt;YouTubeの統合と回避策&amp;lt;/p&amp;gt;
&amp;lt;/dd&amp;gt;
&amp;lt;dt class=&amp;quot;hdlist1&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;スプリント 7-8&amp;lt;/strong&amp;gt;&amp;lt;/dt&amp;gt;
&amp;lt;dd&amp;gt;
&amp;lt;p&amp;gt;高度な音楽的特徴&amp;lt;/p&amp;gt;
&amp;lt;/dd&amp;gt;
&amp;lt;dt class=&amp;quot;hdlist1&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;スプリント 9-10&amp;lt;/strong&amp;gt;&amp;lt;/dt&amp;gt;
&amp;lt;dd&amp;gt;
&amp;lt;p&amp;gt;最適化と生産&amp;lt;/p&amp;gt;
&amp;lt;/dd&amp;gt;
&amp;lt;/dl&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_品質メトリクス&amp;quot;&amp;gt;&amp;lt;a class=&amp;quot;anchor&amp;quot; href=&amp;quot;#_品質メトリクス&amp;quot;&amp;gt;&amp;lt;/a&amp;gt;品質メトリクス&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;各スプリントは次の項目で評価されます：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;ログのカバレッジ&amp;lt;/strong&amp;gt;: &amp;amp;gt;90%のクリティカルパス&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;APIの信頼性&amp;lt;/strong&amp;gt;: &amp;amp;lt;1% の未処理エラー&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;パフォーマンス&amp;lt;/strong&amp;gt;: &amp;amp;lt;500ms平均応答時間&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;保守性&amp;lt;/strong&amp;gt;: サイクロマティック複雑度 &amp;amp;lt;10&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_デプロイメントとモニタリング&amp;quot;&amp;gt;&amp;lt;a class=&amp;quot;anchor&amp;quot; href=&amp;quot;#_デプロイメントとモニタリング&amp;quot;&amp;gt;&amp;lt;/a&amp;gt;デプロイメントとモニタリング&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_本番アーキテクチャ&amp;quot;&amp;gt;&amp;lt;a class=&amp;quot;anchor&amp;quot; href=&amp;quot;#_本番アーキテクチャ&amp;quot;&amp;gt;&amp;lt;/a&amp;gt;本番アーキテクチャ&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
!theme vibrant

cloud &amp;quot;Discordサーバー&amp;quot; {
  [User Commands]
}

node &amp;quot;本番環境&amp;quot; {
  [Discord Bot]
  [Log Aggregator]
  [Metrics Collector]
  [Health Monitor]
}

database &amp;quot;ログストレージ&amp;quot; {
  [Structured Logs]
  [Error Traces]
  [Performance Metrics]
}

cloud &amp;quot;External APIs&amp;quot; {
  [Spotify API]
  [YouTube API]
}

[User Commands] --&amp;amp;gt; [Discord Bot]
[Discord Bot] --&amp;amp;gt; [Log Aggregator]
[Discord Bot] --&amp;amp;gt; [Spotify API]
[Discord Bot] --&amp;amp;gt; [YouTube API]
[Log Aggregator] --&amp;amp;gt; [Structured Logs]
[Metrics Collector] --&amp;amp;gt; [Performance Metrics]
[Health Monitor] --&amp;amp;gt; [Error Traces]

@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_プロアクティブモニタリング&amp;quot;&amp;gt;&amp;lt;a class=&amp;quot;anchor&amp;quot; href=&amp;quot;#_プロアクティブモニタリング&amp;quot;&amp;gt;&amp;lt;/a&amp;gt;プロアクティブモニタリング&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;LDDはインテリジェントなモニタリングを容易にします:&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;ログのパターンに基づくアラート&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;行動異常検出&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;ビジネスメトリクスのリアルタイム&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;ログの相関によるデバッグ支援&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_結論と展望&amp;quot;&amp;gt;&amp;lt;a class=&amp;quot;anchor&amp;quot; href=&amp;quot;#_結論と展望&amp;quot;&amp;gt;&amp;lt;/a&amp;gt;結論と展望&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;この方法論的アプローチは、関数型パラダイムの利点とLog Driven Developmentの堅牢性を組み合わせます。これにより私たちは：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;olist arabic&amp;quot;&amp;gt;
&amp;lt;ol class=&amp;quot;arabic&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;問題を予測する&amp;lt;/strong&amp;gt;事前に設計されたログのおかげで&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;品質を維持する&amp;lt;/strong&amp;gt;継続的な検証によって&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;素早く適応する&amp;lt;/strong&amp;gt;APIの変更に&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;トレーサビリティを確保する&amp;lt;/strong&amp;gt;完全な操作の&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ol&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;反復的な開発とモジュラーアーキテクチャは、音楽プラットフォームの変化する制約に対して拡張性を保証します。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_次のステップ&amp;quot;&amp;gt;&amp;lt;a class=&amp;quot;anchor&amp;quot; href=&amp;quot;#_次のステップ&amp;quot;&amp;gt;&amp;lt;/a&amp;gt;次のステップ&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;フェーズ 1&amp;lt;/strong&amp;gt;: PyMonadeを使用したコアの実装&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;フェーズ 2&amp;lt;/strong&amp;gt;: Spotify インテグレーションとスマートキャッシュ付き&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;フェーズ3&amp;lt;/strong&amp;gt;: 耐性のある YouTube ソリューション&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;フェーズ 4&amp;lt;/strong&amp;gt;: 高度な機能と最適化&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;�堅実な概念的基盤により、技術的な課題を乗り越えながら、例外的なユーザー体験を提供することができます。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;hr&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;この記事は、各コンポーネントの実装と、コード例および関数パターンを詳しく説明する技術シリーズに続くものです。&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;</description>
        </item><item>
            <title>UbuntuでノートPCの温度を冷却し、監視する</title>
            <link >https://cheroliv.com/blog/2025/0083_cold_computer_post.html</link>
            <pubDate>Tue, 15 Jul 2025 00:00:00 +0000</pubDate>
            <guid isPermaLink="false">blog/2025/0083_cold_computer_post.html</guid>
            <description>&amp;lt;div id=&amp;quot;toc&amp;quot; class=&amp;quot;toc&amp;quot;&amp;gt;
&amp;lt;div id=&amp;quot;toctitle&amp;quot;&amp;gt;Table of Contents&amp;lt;/div&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel1&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_このガイドの目的&amp;quot;&amp;gt;このガイドの目的&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_前提条件&amp;quot;&amp;gt;前提条件&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_ツールをインストールして設定する&amp;quot;&amp;gt;ツールをインストールして設定する&amp;lt;/a&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel2&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_lm_sensors_を使ってセンサーを検出する&amp;quot;&amp;gt;lm-sensors` を使ってセンサーを検出する&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_tlp_インテリジェントなエネルギー管理者&amp;quot;&amp;gt;tlp` : インテリジェントなエネルギー管理者&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_cpufrequtils_cpuの周波数を制限する&amp;quot;&amp;gt;cpufrequtils` : CPUの周波数を制限する&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_auto_cpufreq_簡素化された動的管理&amp;quot;&amp;gt;auto-cpufreq` : 簡素化された動的管理&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_thermald_自動熱保護&amp;quot;&amp;gt;thermald` : 自動熱保護&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_リアルタイム監視&amp;quot;&amp;gt;リアルタイム監視&amp;lt;/a&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel2&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_sensors_コマンドラインで&amp;quot;&amp;gt;sensors` コマンドラインで&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_オプション_gui_psensor&amp;quot;&amp;gt;オプション GUI : `psensor&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_追加のコツ&amp;quot;&amp;gt;追加のコツ&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_システムをクリーンアップしてオーバーロードを制限する&amp;quot;&amp;gt;システムをクリーンアップしてオーバーロードを制限する&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_さらに進む&amp;quot;&amp;gt;さらに進む&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_結論&amp;quot;&amp;gt;�📚 結論&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div id=&amp;quot;preamble&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;Ubuntuでノートパソコンが異常に熱くなっていると感じますか？ この記事は、あなたにアプローチを提案します&amp;lt;strong&amp;gt;ソフトウェア&amp;lt;/strong&amp;gt;のための完全な&amp;lt;strong&amp;gt;冷却する&amp;lt;/strong&amp;gt;, &amp;lt;strong&amp;gt;監視する&amp;lt;/strong&amp;gt; et &amp;lt;strong&amp;gt;温度を制御する&amp;lt;/strong&amp;gt;あなたの機械の。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_このガイドの目的&amp;quot;&amp;gt;このガイドの目的&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;コンピュータの全体温度を下げる&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;エネルギー管理を最適化する&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;クリティカルなコンポーネント（CPU、GPUなど）を監視する&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;発生する遅延を避ける&amp;lt;strong&amp;gt;サーマルスロットリング&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
start
:Installer les outils;
:Analyser les capteurs;
:Appliquer des réglages;
note right: cpufreq, tlp, auto-cpufreq
:Surveiller en temps réel;
stop
@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_前提条件&amp;quot;&amp;gt;前提条件&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;Ubuntuマシン (20.04以上推奨)&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;インターネット接続&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;コマンドラインスキル(初級～中級レベル)&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_ツールをインストールして設定する&amp;quot;&amp;gt;ツールをインストールして設定する&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_lm_sensors_を使ってセンサーを検出する&amp;quot;&amp;gt;lm-sensors` を使ってセンサーを検出する&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;sudo apt install lm-sensors
sudo sensors-detect
sensors&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;admonitionblock note&amp;quot;&amp;gt;
&amp;lt;table&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;icon&amp;quot;&amp;gt;
&amp;lt;i class=&amp;quot;fa icon-note&amp;quot; title=&amp;quot;Note&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;
&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;答えてください`YES`すべての質問に関する`sensors-detect`モジュールを検出するために。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/table&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_tlp_インテリジェントなエネルギー管理者&amp;quot;&amp;gt;tlp` : インテリジェントなエネルギー管理者&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;sudo apt install tlp tlp-rdw
sudo systemctl enable tlp
sudo systemctl start tlp&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
(*) --&amp;amp;gt; &amp;quot;TLP はアクティブですか？&amp;quot;
if &amp;quot;はい&amp;quot; then
  --&amp;amp;gt; [yes] &amp;quot;消費削減&amp;quot;
  --&amp;amp;gt; &amp;quot;CPUの周波数制限&amp;quot;
else
  --&amp;amp;gt; [no] &amp;quot;TLP の起動&amp;quot;
  --&amp;amp;gt; &amp;quot;自動アクティベーション&amp;quot;
endif
--&amp;amp;gt;(*)
@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_cpufrequtils_cpuの周波数を制限する&amp;quot;&amp;gt;cpufrequtils` : CPUの周波数を制限する&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;sudo apt install cpufrequtils
cpufreq-info
sudo cpufreq-set -g powersave&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;code&amp;gt;powersave&amp;lt;/code&amp;gt;: 周波数のピークを制限します&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;code&amp;gt;performance&amp;lt;/code&amp;gt;: 電力を優先し、温度を犠牲にする&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_auto_cpufreq_簡素化された動的管理&amp;quot;&amp;gt;auto-cpufreq` : 簡素化された動的管理&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;git clone https://github.com/AdnanHodzic/auto-cpufreq.git
cd auto-cpufreq
sudo ./auto-cpufreq-installer
sudo auto-cpufreq --install&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
start
:Analyse charge système;
:Réglage fréquence CPU;
:Vérification température;
:Adaptation dynamique;
stop
@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_thermald_自動熱保護&amp;quot;&amp;gt;thermald` : 自動熱保護&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;sudo apt install thermald
sudo systemctl enable thermald
sudo systemctl start thermald&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_リアルタイム監視&amp;quot;&amp;gt;リアルタイム監視&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_sensors_コマンドラインで&amp;quot;&amp;gt;sensors` コマンドラインで&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;watch -n 2 sensors&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_オプション_gui_psensor&amp;quot;&amp;gt;オプション GUI : `psensor&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;sudo apt install psensor&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;シンプルなグラフィカルインターフェース CPU、GPU、ファン用。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_追加のコツ&amp;quot;&amp;gt;追加のコツ&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;タブと重いアプリケーション（例: ブラウザ）を閉じる&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;バッテリーでの過度な使用を避ける&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;プロセスを介して監視`htop`:&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;sudo apt install htop
htop&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_システムをクリーンアップしてオーバーロードを制限する&amp;quot;&amp;gt;システムをクリーンアップしてオーバーロードを制限する&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;sudo apt autoremove
sudo apt autoclean
sudo journalctl --vacuum-time=3d&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_さらに進む&amp;quot;&amp;gt;さらに進む&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;サービスを作成できます`systemd`カスタマイズして起動時に特定の設定を自動的に適用する 次の記事で例をご希望ですか？お知らせください！&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_結論&amp;quot;&amp;gt;�📚 結論&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;これらのシンプルなツールを組み合わせると、あなたは得られるでしょう：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;管理されたCPU温度&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;�換気の騒音が少ない&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;より良い自律性&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;温度を定期的に監視し、過熱を防いでください。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;em&amp;gt;__&amp;lt;/em&amp;gt; CPUを溶かすよりも、予防する方がいい。 (Empty output)&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;</description>
        </item><item>
            <title>デバッグの記録：Bootstrap 5でFirefoxの気まぐれを制御する</title>
            <link >https://cheroliv.com/blog/2025/0082_ui_struggle_post.html</link>
            <pubDate>Mon, 14 Jul 2025 00:00:00 +0000</pubDate>
            <guid isPermaLink="false">blog/2025/0082_ui_struggle_post.html</guid>
            <description>&amp;lt;div id=&amp;quot;toc&amp;quot; class=&amp;quot;toc&amp;quot;&amp;gt;
&amp;lt;div id=&amp;quot;toctitle&amp;quot;&amp;gt;Sommaire&amp;lt;/div&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel1&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_戦場モックアップ三つのブラウザー複数のレンダリング&amp;quot;&amp;gt;戦場：モックアップ、三つのブラウザー、複数のレンダリング&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_問題1ヒーローセクションの飛ぶカード&amp;quot;&amp;gt;問題1：ヒーローセクションの飛ぶカード&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_問題2食人ナビゲーションバー&amp;quot;&amp;gt;問題2：食人ナビゲーションバー&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_問題3無秩序なタイポグラフィー&amp;quot;&amp;gt;問題3：無秩序なタイポグラフィー&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_問題4オーバーフローするナビゲーションバー&amp;quot;&amp;gt;問題4：オーバーフローするナビゲーションバー&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_問題5見えないハンバーガーメニュー&amp;quot;&amp;gt;問題5：見えないハンバーガーメニュー&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_結論執拗なデバッグから得た教訓&amp;quot;&amp;gt;結論：執拗なデバッグから得た教訓&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div id=&amp;quot;preamble&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;admonitionblock note&amp;quot;&amp;gt;
&amp;lt;table&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;icon&amp;quot;&amp;gt;
&amp;lt;i class=&amp;quot;fa icon-note&amp;quot; title=&amp;quot;Note&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;
&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;読了時間：&amp;lt;/strong&amp;gt; 約7分 &amp;lt;strong&amp;gt;レベル：&amp;lt;/strong&amp;gt; 中級&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/table&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;この詳細な実践ケースでは、Bootstrap 5.2 を使用した UI モックアップの作成時に遭遇する最も一般的で、時として最もフラストレーションを引き起こすブラウザ互換性の問題を解剖します。Flexbox の管理からフォントレンダリングの微妙さまで、私たちのデバッグプロセスを紹介し、Firefox で崩れたデザインをすべてのブラウザでピクセルパーフェクトな体験に変える方法を学びます。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;hr&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_戦場モックアップ三つのブラウザー複数のレンダリング&amp;quot;&amp;gt;戦場：モックアップ、三つのブラウザー、複数のレンダリング&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;すべてのフロントエンド開発者はこの感覚を知っている。何時間も作業して、ようやくデザインが完璧になる。配置は正確で、タイポグラフィはエレガント、アニメーションは滑らかである。満足のため息をつき、Chrome（またはBrave、またはEdge）で自分の作品を称賛し、さらに念のためにFirefoxでプロジェクトを開く。すると、そこが悲劇の始まりだ。要素がはみ出し、配置が崩れ、フォントのサイズが乱れ…美しい調和はかき消えてしまった。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;これは、新しいポートフォリオインターフェースを開発する際に直面したまさにそのシナリオです。要件はシンプルで、モダンでレスポンシブなホームページ、テーマセレクター（ライト、ダーク、ハイコントラスト）を備え、&amp;lt;strong&amp;gt;vanilla JavaScript&amp;lt;/strong&amp;gt; と &amp;lt;strong&amp;gt;Bootstrap 5.2&amp;lt;/strong&amp;gt; の最新バージョンを使用すること。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;この記事は奇跡的な解決策のリストではありません。これは私たちのデバッグセッションのログであり、Blinkエンジン（Chromium、Brave）とGeckoエンジン（Firefox）間のレンダリングの違いの「なぜ」に深く迫るものであり、堅牢で現代的な解決策が常に急ごしらえのパッチよりも優れていることを示しています。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;ユースケース図 : デバッグプロセス&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
left to right direction
actor &amp;quot;フロントエンド開発者&amp;quot; as Dev

rectangle &amp;quot;モックアップ UI Bootstrap 5&amp;quot; {
  usecase &amp;quot;Flexboxのアライメントを修正する&amp;quot; as UC1
  usecase &amp;quot;パディングを動的に調整する（JS）&amp;quot; as UC2
  usecase &amp;quot;タイポグラフィを制御する (clamp())&amp;quot; as UC3
  usecase &amp;quot;メニューのオーバーフローを解決する&amp;quot; as UC4
  usecase &amp;quot;メニューのアイコンを表示する&amp;quot; as UC5
}

actor &amp;quot;Firefox ブラウザ&amp;quot; as Firefox

Dev -- (UC1)
Dev -- (UC2)
Dev -- (UC3)
Dev -- (UC4)
Dev -- (UC5)

(UC1) ..&amp;amp;gt; Firefox : &amp;amp;lt;&amp;amp;lt;extend&amp;amp;gt;&amp;amp;gt;
(UC2) ..&amp;amp;gt; Firefox : &amp;amp;lt;&amp;amp;lt;extend&amp;amp;gt;&amp;amp;gt;
(UC3) ..&amp;amp;gt; Firefox : &amp;amp;lt;&amp;amp;lt;extend&amp;amp;gt;&amp;amp;gt;
(UC4) ..&amp;amp;gt; Firefox : &amp;amp;lt;&amp;amp;lt;extend&amp;amp;gt;&amp;amp;gt;
(UC5) ..&amp;amp;gt; Firefox : &amp;amp;lt;&amp;amp;lt;extend&amp;amp;gt;&amp;amp;gt;

note right of Firefox : Révèle les problèmes de compatibilité
@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;コンポーネント図 : フロントエンドソリューションのアーキテクチャ&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
!theme plain

package &amp;quot;フロントエンドソリューション&amp;quot; {
  component &amp;quot;HTML (テンプレート FTL)&amp;quot; as HTML
  component &amp;quot;script.js&amp;quot; as JS
  component &amp;quot;styles.css&amp;quot; as CSS

  interface &amp;quot;DOMの操作&amp;quot; as iDOM
  interface &amp;quot;CSSの修正&amp;quot; as iCSS
}

package &amp;quot;フレームワーク&amp;quot; {
  component &amp;quot;Bootstrap 5.2&amp;quot; as BS
  interface &amp;quot;CSS変数&amp;quot; as iVars
  interface &amp;quot;ユーティリティクラス&amp;quot; as iUtils
}

HTML ..&amp;amp;gt; iDOM : nécessite
JS ..&amp;amp;gt; iDOM : réalise

HTML ..&amp;amp;gt; iCSS : nécessite
CSS ..&amp;amp;gt; iCSS : réalise

CSS ..&amp;amp;gt; iVars : nécessite
BS ..&amp;amp;gt; iVars : fournit

HTML ..&amp;amp;gt; iUtils : utilise
BS ..&amp;amp;gt; iUtils : fournit

note right of JS
  - Mesure la hauteur de la navbar
  - Applique le padding dynamiquement
end note

note right of CSS
  - Utilise clamp() pour la typographie
  - Réduit les marges du menu
  - Surcharge l&amp;#39;icône du menu via les variables
end note

@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_問題1ヒーローセクションの飛ぶカード&amp;quot;&amp;gt;問題1：ヒーローセクションの飛ぶカード&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;最初のバグはまた最も目立つものでした。ウェルカムセクション (&amp;quot;hero&amp;quot;) は、2列で構成されています：左側にメインタイトル、右側に紹介カード。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;症状 :&amp;lt;/strong&amp;gt;ChromeとBraveでは、2つの列は垂直方向に完璧に中央揃えられていました。 Firefoxでは、右のカードが説明不能なほど左のテキストの下に落ちました。&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;調査：&amp;lt;/strong&amp;gt;HTMLコードは単純で正しそうに見えましたが、Bootstrapの標準クラスを使用していました。&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-html hljs&amp;quot; data-lang=&amp;quot;html&amp;quot;&amp;gt;&amp;amp;lt;section id=&amp;quot;home&amp;quot; class=&amp;quot;hero-section&amp;quot;&amp;amp;gt;
    &amp;amp;lt;div class=&amp;quot;container&amp;quot;&amp;amp;gt;
        &amp;amp;lt;!-- Cette ligne est la clé du problème --&amp;amp;gt;
        &amp;amp;lt;div class=&amp;quot;row align-items-center min-vh-100&amp;quot;&amp;amp;gt;
            &amp;amp;lt;div class=&amp;quot;col-lg-6&amp;quot;&amp;amp;gt;
                &amp;amp;lt;!-- Contenu de gauche --&amp;amp;gt;
            &amp;amp;lt;/div&amp;amp;gt;
            &amp;amp;lt;div class=&amp;quot;col-lg-6&amp;quot;&amp;amp;gt;
                &amp;amp;lt;!-- Carte de droite --&amp;amp;gt;
            &amp;amp;lt;/div&amp;amp;gt;
        &amp;amp;lt;/div&amp;amp;gt;
    &amp;amp;lt;/div&amp;amp;gt;
&amp;amp;lt;/section&amp;amp;gt;&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;私たちのカスタムCSS`.hero-section`定義していた`display: flex` et &amp;lt;code&amp;gt;align-items: center&amp;lt;/code&amp;gt;，そしてクラス`min-vh-100`行に最小の高さを与えていた (&amp;lt;code&amp;gt;div.row&amp;lt;/code&amp;gt;). それでは、なぜFirefoxは列を中央揃えにしなかったのですか？&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;根本原因：&amp;lt;/strong&amp;gt;これはレンダリングエンジンが暗黙の高さをどのように解釈するかの教科書的な例です。その`&amp;amp;lt;section&amp;amp;gt;`持っていた`min-height`, でも`height`明示的。適用するために`align-items-center`中に`div.row`, Firefoxはこのコンテナの参照の高さを知る必要があります。その親要素と同じように (&amp;lt;code&amp;gt;div.container&amp;lt;/code&amp;gt; et la `&amp;amp;lt;section&amp;amp;gt;`それ自身には高さがなかった&amp;lt;strong&amp;gt;�厳しい&amp;lt;/strong&amp;gt;Firefoxは行き詰まっていた。より許容的なBlinkエンジンは、意図を&amp;quot;推測&amp;quot;し、要素を中央に揃えることができる。仕様に忠実なGeckoはそれを行わない。&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;解決策 :&amp;lt;/strong&amp;gt;高さを明示的にする。私たちは強制した`.container` et le `.row`それぞれの親の高さの100%を占有するために、ユーティリティクラスを使用する`h-100`の Bootstrap.&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-html hljs&amp;quot; data-lang=&amp;quot;html&amp;quot;&amp;gt;&amp;amp;lt;section id=&amp;quot;home&amp;quot; class=&amp;quot;hero-section&amp;quot;&amp;amp;gt;
    &amp;amp;lt;div class=&amp;quot;container h-100&amp;quot;&amp;amp;gt;
        &amp;amp;lt;div class=&amp;quot;row align-items-center min-vh-100 h-100&amp;quot;&amp;amp;gt;
            &amp;amp;lt;!-- ... --&amp;amp;gt;
        &amp;amp;lt;/div&amp;amp;gt;
    &amp;amp;lt;/div&amp;amp;gt;
&amp;amp;lt;/section&amp;amp;gt;&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;admonitionblock tip&amp;quot;&amp;gt;
&amp;lt;table&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;icon&amp;quot;&amp;gt;
&amp;lt;i class=&amp;quot;fa icon-tip&amp;quot; title=&amp;quot;Tip&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;
&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;の`align-items`Flexbox は垂直軸で期待通りに機能しません。常にコンテナに高さがあることを確認してください。&amp;lt;code&amp;gt;height&amp;lt;/code&amp;gt; ou &amp;lt;code&amp;gt;min-height&amp;lt;/code&amp;gt;) 定義されており、問題が続く場合（特にFirefoxでは）、中間コンテナがこの高さを適切に伝播するようにしてください。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/table&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_問題2食人ナビゲーションバー&amp;quot;&amp;gt;問題2：食人ナビゲーションバー&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;「Hero」セクションが配置された後、別の問題が発生しました：ナビゲーションバーとそのクラス`fixed-top`, タイトルに重なっていました。Un`padding-top: 80px`これは&amp;quot;Hero&amp;quot;セクションに解決策として適用されていた。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;症状：&amp;lt;/strong&amp;gt; Le `padding`Chromeでは十分だったが、Firefoxではそうではなく、タイトルは常に一部がマスクされたままだった。&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;根本原因：&amp;lt;/strong&amp;gt;「マジックナンバー」の使用 (&amp;lt;code&amp;gt;80px&amp;lt;/code&amp;gt;) は非常に悪い習慣です。ナビゲーションバーのような要素の高さは、フォントのレンダリング、間隔、あるいはユーザー設定の微妙な違いにより、ブラウザごとに数ピクセル変わることがあります。固定値に頼るのは、脆弱なデザインへのレシピです。&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;解決策：&amp;lt;/strong&amp;gt;JavaScriptでの動的で確実な解決策。 私たちは：のために小さなスクリプトを書きました&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;ページのレンダリング後のナビゲーションバーの*実際の*高さを測定する。&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;この測定した高さを適用する`padding-top`セクション「Hero」。&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;ウィンドウのサイズが変更されるたびにこの関数を再実行し、変更に対応させる（ハンバーガーメニューへの切り替えなど）。&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-javascript hljs&amp;quot; data-lang=&amp;quot;javascript&amp;quot;&amp;gt;document.addEventListener(&amp;#39;DOMContentLoaded&amp;#39;, function() {
    function adjustHeroPadding() {
        const navbar = document.querySelector(&amp;#39;.navbar.fixed-top&amp;#39;);
        const heroSection = document.querySelector(&amp;#39;.hero-section&amp;#39;);

        if (navbar &amp;amp;amp;&amp;amp;amp; heroSection) {
            const navbarHeight = navbar.offsetHeight;
            heroSection.style.paddingTop = navbarHeight + &amp;#39;px&amp;#39;;
        }
    }

    // Ajuster au chargement et au redimensionnement
    adjustHeroPadding();
    window.addEventListener(&amp;#39;resize&amp;#39;, adjustHeroPadding);
});&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;シーケンス図 : パディングの動的調整&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
title 人食いナビゲーションバーの問題の解決策
actor Utilisateur
participant &amp;quot;ブラウザ&amp;quot; as Browser
participant &amp;quot;script.js&amp;quot; as JS
participant &amp;quot;DOM&amp;quot; as DOM

Utilisateur -&amp;amp;gt; Browser: Charge la page
activate Browser

Browser -&amp;amp;gt; JS: Déclenche l&amp;#39;événement &amp;#39;DOMContentLoaded&amp;#39;
activate JS

JS -&amp;amp;gt; DOM: querySelector(&amp;#39;.navbar.fixed-top&amp;#39;)
activate DOM
DOM --&amp;amp;gt; JS: Retourne l&amp;#39;élément Navbar
deactivate DOM

JS -&amp;amp;gt; DOM: querySelector(&amp;#39;.hero-section&amp;#39;)
activate DOM
DOM --&amp;amp;gt; JS: Retourne l&amp;#39;élément Hero
deactivate DOM

JS -&amp;amp;gt; DOM: navbar.offsetHeight
activate DOM
DOM --&amp;amp;gt; JS: Retourne la hauteur calculée (ex: 83px)
deactivate DOM

JS -&amp;amp;gt; DOM: heroSection.style.paddingTop = &amp;quot;83px&amp;quot;
activate DOM
deactivate DOM

deactivate JS
deactivate Browser

... Plus tard ...

Utilisateur -&amp;amp;gt; Browser: Redimensionne la fenêtre
activate Browser
Browser -&amp;amp;gt; JS: Déclenche l&amp;#39;événement &amp;#39;resize&amp;#39;
activate JS
JS -&amp;amp;gt; JS: Exécute à nouveau adjustHeroPadding()
note right of JS: Le processus de mesure et\nd&amp;#39;application du padding se répète.
deactivate JS
deactivate Browser

@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;並行して、もちろんルールを削除しました`padding-top: 80px;`私たちのファイルの`styles.css`。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_問題3無秩序なタイポグラフィー&amp;quot;&amp;gt;問題3：無秩序なタイポグラフィー&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;次の懸念はブランドイメージに最も有害だった：見出しのサイズ。&amp;lt;/div&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;�症状：&amp;lt;/strong&amp;gt;Firefoxでは、タイトル &amp;quot;Développeur Formateur&amp;amp;#8230;&amp;amp;#8203;&amp;quot; のフォントが巨大で、ほとんど衝撃的だったのに対し、他のブラウザーでは調和が取れていた。&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;根本的な原因：&amp;lt;/strong&amp;gt;タイトルはクラスを使用していました`display-4`Bootstrap のこれらのクラスは、レスポンシブなフォントサイズを使用し、しばしば単位に基づいています。`rem`メディアクエリも含みます。もう一度、Firefoxのレンダリングアルゴリズムと「Inter」フォントの組み合わせにより、1920x1080の解像度で文字サイズの計算がはるかに大きくなりました。&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;解決策：&amp;lt;/strong&amp;gt;CSS関数を使ってコントロールを取り戻す`clamp()&amp;lt;code&amp;gt;. この機能はフローディタイポグラフィに革命をもたらします。これにより、3つの値でフォントサイズを定義できます： 最小サイズ、および「推奨」サイズ（ビューの幅に適応する、`vw&amp;lt;/code&amp;gt;), そして最大のサイズ。&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-css hljs&amp;quot; data-lang=&amp;quot;css&amp;quot;&amp;gt;.hero-content h1 {
    color: var(--text-primary);
    line-height: 1.2;
    /*
       Min: 2rem
       Préférée: s&amp;#39;adapte à la vue
       Max: 2.5rem (40px)
    */
    font-size: clamp(2rem, 1.2rem + 1.5vw, 2.5rem);
}&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;と`clamp()&amp;lt;code&amp;gt;, ブラウザに「画面に合わせてフォントを大きくして、ただし超えないように」と伝えることができました。&amp;lt;strong&amp;gt;決して&amp;lt;/strong&amp;gt;の限界`2.5rem&amp;lt;/code&amp;gt;. これはすべてのブラウザでのレンダリングを瞬時に統一し、最終的な美観に対する絶対的なコントロールを得ることができました。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_問題4オーバーフローするナビゲーションバー&amp;quot;&amp;gt;問題4：オーバーフローするナビゲーションバー&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;これが私たちに最も手間取らせた問題であり、最終的にレンダリングの微妙な違いの本質を明らかにした。&amp;lt;/div&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;�症状：&amp;lt;/strong&amp;gt;1920x1080の画面では、メニューの最後のリンク（「Blog」、「Contact」）が画面の右側に押し出されていましたが、Firefoxだけで起きていました。&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;根本的な原因：&amp;lt;/strong&amp;gt;いくつかの失敗した試みの後 （Bootstrapのブレークポイントを変更する`lg` à &amp;lt;code&amp;gt;xl`それから`xxl&amp;lt;/code&amp;gt;), 私たちは理解しました。原因はBootstrapのロジックではなく、単純な幅の計算でした。Firefoxでは、すべてのリンクの幅の合計、それらのを含む`padding` et `margin`サブピクセル単位まで、それは &amp;lt;strong&amp;gt;やや&amp;lt;/strong&amp;gt; 1920 ピクセルを上回っていました。 Chromeでは、同じ合計は &amp;lt;strong&amp;gt;やや&amp;lt;/strong&amp;gt; 小さかった。 いくつかのピクセルが足りませんでした。&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;解決策：&amp;lt;/strong&amp;gt;外科的な間隔の削減。Firefoxを特定的に対象とする古いCSSの「ハック」を使用するわけにはいかなかったため、唯一のきれいな解決策は、どこでも機能する共通のスタイルを見つけることでした。したがって、各ナビゲーションリンクの水平マージンとパディングをわずかに縮小しました。&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-css hljs&amp;quot; data-lang=&amp;quot;css&amp;quot;&amp;gt;/* La version finale, légèrement plus compacte */
.navbar-nav .nav-link {
    font-size: 0.9rem; /* 90% de la taille de base */
    color: var(--text-primary) !important;
    font-weight: 500;
    margin: 0 0.2rem;
    padding: 0.5rem 0.5rem !important;
    border-radius: 0.375rem;
    transition: all 0.3s ease;
}&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;この削減は、単一の要素では肉眼ではほとんど見えないほど小さいものですが、これによりFirefoxで全てのリンクが枠内に収まるために必要なスペースを集団として確保でき、他のブラウザーではほぼ同じ外観を保っています。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_問題5見えないハンバーガーメニュー&amp;quot;&amp;gt;問題5：見えないハンバーガーメニュー&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;最後の問題、しかも軽視できない問題は、モバイルでのアクセシビリティに関するものでした。&amp;lt;/div&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;症状 :&amp;lt;/strong&amp;gt;レスポンシブモード（ハンバーガーメニュー）では、ダークテーマおよびハイコントラストテーマでメニューアイコンが見えませんでした。&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;根本的な原因:&amp;lt;/strong&amp;gt;Bootstrap 5のメニューのアイコンは`background-image`(URLエンコードされた SVG). デフォルトでは、そのストロークの色は暗く、明るい背景に最適化されています。 それはテーマの変更に自動的には適応しません。&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;解決策 :&amp;lt;/strong&amp;gt;Bootstrap の CSS 変数を使用してアイコンを上書きします。白いストロークの新しい SVG アイコンを定義しましたが、&amp;lt;code&amp;gt;#ffffff&amp;lt;/code&amp;gt;)、そして私たちはそれを具体的に適用しましたときにテーマ`dark` ou &amp;lt;code&amp;gt;high-contrast&amp;lt;/code&amp;gt;�稼働している。&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-css hljs&amp;quot; data-lang=&amp;quot;css&amp;quot;&amp;gt;/* ======================
   Fix pour l&amp;#39;icône du menu Burger (Blanc)
   ====================== */
[data-bs-theme=&amp;quot;dark&amp;quot;] .navbar-toggler-icon,
[data-bs-theme=&amp;quot;high-contrast&amp;quot;] .navbar-toggler-icon {
    --bs-navbar-toggler-icon-bg: url(&amp;quot;data:image/svg+xml,%3csvg xmlns=&amp;#39;http://www.w3.org/2000/svg&amp;#39; viewBox=&amp;#39;0 0 30 30&amp;#39;%3e%3cpath stroke=&amp;#39;%23ffffff&amp;#39; stroke-linecap=&amp;#39;round&amp;#39; stroke-miterlimit=&amp;#39;10&amp;#39; stroke-width=&amp;#39;2&amp;#39; d=&amp;#39;M4 7h22M4 15h22M4 23h22&amp;#39;/%3e%3c/svg%3e&amp;quot;);
}&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;admonitionblock important&amp;quot;&amp;gt;
&amp;lt;table&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;icon&amp;quot;&amp;gt;
&amp;lt;i class=&amp;quot;fa icon-important&amp;quot; title=&amp;quot;Important&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;
&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;Bootstrap のこのようなコンポーネントのカスタマイズは、CSS 変数のオーバーライドを介してますます行われています (&amp;lt;code&amp;gt;--bs-component-property&amp;lt;/code&amp;gt;), これは最も清潔で持続可能な方法です。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/table&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_結論執拗なデバッグから得た教訓&amp;quot;&amp;gt;結論：執拗なデバッグから得た教訓&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;この道のり、時々苛立たしいかもしれないが、学びに満ちている。それぞれの解決された問題は、ウェブ開発の基本的な真実を強化する：&amp;lt;strong&amp;gt;厳格なマルチブラウザテストに代わりになるものは何もない&amp;lt;/strong&amp;gt;。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;マインドマップ : デバッグと学んだ教訓のまとめ&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startmindmap
+ Débogage Cross-Browser : Bootstrap 5
++ **Conflit :** Chrome (Blink) vs Firefox (Gecko)
++ **Problème 1 : Alignement Hero**
+++ Cause : Hauteur implicite
+++ Solution : Classe `.h-100`
++ **Problème 2 : Navbar Cannibale**
+++ Cause : &amp;quot;マジックナンバー&amp;quot; (padding fixe)
+++ Solution : JS `offsetHeight`
++ **Problème 3 : Typographie Géante**
+++ Cause : Rendu des `rem`
+++ Solution : CSS `clamp()`
++ **Problème 4 : Menu qui déborde**
+++ Cause : Calcul de largeur sub-pixel
+++ Solution : Réduction des marges/paddings
++ **Problème 5 : Icône Invisible**
+++ Cause : SVG non adaptable au thème
+++ Solution : Surcharge de variable CSS
++ **Leçons Clés**
+++ Firefox force un code robuste
+++ Fuir les &amp;quot;マジックナンバー&amp;quot;
+++ Maîtriser la typographie fluide
+++ Personnaliser via les variables CSS
@endmindmap&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;olist arabic&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;これが私たちが保持している教訓 :&amp;lt;/div&amp;gt;
&amp;lt;ol class=&amp;quot;arabic&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;Firefoxは味方です :&amp;lt;/strong&amp;gt;CSS標準への最高の適合性が、より堅牢で曖昧さの少ないコードを書くよう私たちを強制する。&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;「魔法の数」を避けて :&amp;lt;/strong&amp;gt;固定値 (のように`padding-top: 80px`) は時限爆弾です。常に動的なソリューション（JavaScript）または相対的なソリューション（Flexbox、Grid）を好むべきです。&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;タイポグラフィをマスター：&amp;lt;/strong&amp;gt;使ってください`clamp()`レスポンシブフォントのサイズを完全に制御するために。&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;「コンポーネント」を考えて：&amp;lt;/strong&amp;gt;Bootstrapをカスタマイズするには、フレームワークを上書きするルールを増やすのではなく、そのCSS変数を上書きしてください。&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;ブラウザを対象としないで：&amp;lt;/strong&amp;gt;解決策はほとんどの場合、特定のブラウザ向けに &amp;quot;hack&amp;quot; を行うことではなく、どこでも機能する共通のスタイルを見つけることです。&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ol&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;最終的に、モックアップは堅牢で予測可能になり、テンプレートシステムに組み込む準備が整いました。修正されたバグは失敗ではなく、より良いコードへ向けた一歩でした。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;</description>
        </item><item>
            <title>Gradleユニットテストの課題を `gradle.properties` で解決する</title>
            <link >https://cheroliv.com/blog/2025/0081_TDD_Gradle_Properties_Fix_post.html</link>
            <pubDate>Sun, 13 Jul 2025 00:00:00 +0000</pubDate>
            <guid isPermaLink="false">blog/2025/0081_TDD_Gradle_Properties_Fix_post.html</guid>
            <description>&amp;lt;div id=&amp;quot;toc&amp;quot; class=&amp;quot;toc&amp;quot;&amp;gt;
&amp;lt;div id=&amp;quot;toctitle&amp;quot;&amp;gt;Sommaire&amp;lt;/div&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel1&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_問題_gradleプラグインのユニットテストを分離する&amp;quot;&amp;gt;問題: Gradleプラグインのユニットテストを分離する&amp;lt;/a&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel2&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_問題のアーキテクチャ&amp;quot;&amp;gt;問題のアーキテクチャ&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_偽りの良いアイデアへの誘惑&amp;quot;&amp;gt;偽りの良いアイデアへの誘惑&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_ソリューション_extrapropertiesextension_を使ってプロパティをシミュレートする&amp;quot;&amp;gt;ソリューション : &amp;lt;code&amp;gt;ExtraPropertiesExtension&amp;lt;/code&amp;gt; を使ってプロパティをシミュレートする&amp;lt;/a&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel2&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_ステップ_1_extrapropertiesextensionを理解する&amp;quot;&amp;gt;ステップ 1 : ExtraPropertiesExtensionを理解する&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_ステップ_2_テストのセットアップ_準備&amp;quot;&amp;gt;ステップ 2: テストのセットアップ - 準備&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_ステップ_3プロパティの注入&amp;quot;&amp;gt;ステップ 3：プロパティの注入&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_ステップ4ソリューションフロー図&amp;quot;&amp;gt;ステップ4：ソリューションフロー図&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_ステップ_5_前後比較&amp;quot;&amp;gt;ステップ 5 : 前後比較&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_ステップ6_複数のテストケースの管理&amp;quot;&amp;gt;ステップ6: 複数のテストケースの管理&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_ソリューションの最終アーキテクチャ&amp;quot;&amp;gt;ソリューションの最終アーキテクチャ&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_このアプローチの利点&amp;quot;&amp;gt;このアプローチの利点&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_ベストプラクティスとアドバイス&amp;quot;&amp;gt;ベストプラクティスとアドバイス&amp;lt;/a&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel2&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_ユーティリティメソッドを作成する&amp;quot;&amp;gt;ユーティリティメソッドを作成する&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_プロパティの検証&amp;quot;&amp;gt;プロパティの検証&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_結論&amp;quot;&amp;gt;結論&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_問題_gradleプラグインのユニットテストを分離する&amp;quot;&amp;gt;問題: Gradleプラグインのユニットテストを分離する&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;Gradleプラグインのユニットテストを書く際の一般的な課題は、プロジェクト設定への依存関係を管理すること、ファイルに定義されたプロパティなど`gradle.properties`. 私たちのケースでは、プラグイン`jbake.ghpages`プロパティを読む必要があった`site_config_path`正常に機能するために。 タスクの単体テスト`initialize`彼はこのプロパティが存在するときのプラグインの動作を確認しなければならなかった。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;根本的な問題は、単体テストは設計上、&amp;lt;strong&amp;gt;孤立している&amp;lt;/strong&amp;gt; 必要があるということです。使用法は`ProjectBuilder`Gradleのインスタンスを作成する`Project`メモリ上にあり、ファイルシステム上の実際のプロジェクトから完全に切り離されている。 したがって、このテスト インスタンスは自動的にファイルを読み込まない`gradle.properties`したがって、そのプロパティについて知識を持っていない`site_config_path`.&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_問題のアーキテクチャ&amp;quot;&amp;gt;問題のアーキテクチャ&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;次の図は、テスト環境とファイルシステムの切断を示しています：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
!define RECTANGLE class

package &amp;quot;本番環境&amp;quot; {
  RECTANGLE ProjectReal {
    + build.gradle.kts
    + gradle.properties
    + src/
  }

  RECTANGLE GradleProperties {
    site_config_path=src/jbake/settings/site.yml
  }

  RECTANGLE JbakePlugin {
    - readProperty(name: String)
    + initialize()
  }

  ProjectReal --&amp;amp;gt; GradleProperties : lit au démarrage
  JbakePlugin --&amp;amp;gt; GradleProperties : accède via project.properties
}

package &amp;quot;テスト環境&amp;quot; {
  RECTANGLE ProjectTest {
    + Créé par ProjectBuilder
    + En mémoire uniquement
    + Pas de gradle.properties
  }

  RECTANGLE JbakePluginTest {
    + testInitialize()
  }

  ProjectTest -[#red]x GradleProperties : ❌ Pas d&amp;#39;accès
  JbakePluginTest --&amp;amp;gt; ProjectTest : utilise
}

note right of ProjectTest : Isolation = Pas d&amp;#39;accès\nau système de fichiers
@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_偽りの良いアイデアへの誘惑&amp;quot;&amp;gt;偽りの良いアイデアへの誘惑&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;最初のアプローチとしては、ファイルを作成することが考えられます。`gradle.properties`テストのリソースにおける架空の&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-text hljs&amp;quot; data-lang=&amp;quot;text&amp;quot;&amp;gt;// src/test/resources/gradle.properties
site_config_path=src/jbake/settings/site.yml&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;しかし、この方法は失敗する運命にあるため`ProjectBuilder`これはファイルシステムをスキャンして設定ファイルを探すようには設計されていません。テストは孤立した状態のまま残り、このファイルを無視します。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_ソリューション_extrapropertiesextension_を使ってプロパティをシミュレートする&amp;quot;&amp;gt;ソリューション : &amp;lt;code&amp;gt;ExtraPropertiesExtension&amp;lt;/code&amp;gt; を使ってプロパティをシミュレートする&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;この問題のエレガントな解決策は、ファイルを*読む*ことではなく、オブジェクトに直接プロパティの存在を*シミュレート*することです。`Project`テスト。 Gradle はこれを行うための強力なメカニズムを提供しています： &amp;lt;strong&amp;gt;追加プロパティ&amp;lt;/strong&amp;gt; (追加プロパティ)。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_ステップ_1_extrapropertiesextensionを理解する&amp;quot;&amp;gt;ステップ 1 : ExtraPropertiesExtensionを理解する&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;`ExtraPropertiesExtension`Gradleモデルの各オブジェクトに添付されたキー値コンテナです。プロジェクト、タスク、またはその他のGradle拡張に動的にプロパティを追加することができます。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
!define RECTANGLE class

RECTANGLE Project {
  + name: String
  + version: String
  + extensions: ExtensionContainer
  + properties: Map&amp;amp;lt;String, ?&amp;amp;gt;
}

RECTANGLE ExtensionContainer {
  + getByType(Class&amp;amp;lt;T&amp;amp;gt;): T
  + add(String, Object): void
}

RECTANGLE ExtraPropertiesExtension {
  + set(String, Object): void
  + get(String): Object
  + has(String): boolean
  + getProperties(): Map&amp;amp;lt;String, Object&amp;amp;gt;
}

Project --&amp;amp;gt; ExtensionContainer : contient
ExtensionContainer --&amp;amp;gt; ExtraPropertiesExtension : gère
ExtraPropertiesExtension --&amp;amp;gt; Project : synchronise avec\nproject.properties

note right of ExtraPropertiesExtension : Point d&amp;#39;entrée pour\ninjecter des propriétés
@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_ステップ_2_テストのセットアップ_準備&amp;quot;&amp;gt;ステップ 2: テストのセットアップ - 準備&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;まず、私たちの単体テストの基本構造を作成しましょう :&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;JbakeGhPagesPluginTest.kt - Structure de base&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-kotlin hljs&amp;quot; data-lang=&amp;quot;kotlin&amp;quot;&amp;gt;class JbakeGhPagesPluginTest {

    @TempDir
    lateinit var testProjectDir: File

    @Test
    fun `check initialize and config yaml file if not existing`() {
        // Étape 1 : Créer un projet de test isolé
        val project = ProjectBuilder.builder()
            .withProjectDir(testProjectDir)
            .build()

        // Suite des étapes...
    }
}&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_ステップ_3プロパティの注入&amp;quot;&amp;gt;ステップ 3：プロパティの注入&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;テストプロジェクトにプロパティを注入する詳細なプロセスは次のとおりです：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;JbakeGhPagesPluginTest.kt - Injection complète&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-kotlin hljs&amp;quot; data-lang=&amp;quot;kotlin&amp;quot;&amp;gt;@Test
fun `check initialize and config yaml file if not existing`() {
    // Étape 1 : Créer un projet de test isolé en mémoire
    val project = ProjectBuilder.builder()
        .withProjectDir(testProjectDir)
        .build()

    // Étape 2 : Récupérer le gestionnaire de propriétés supplémentaires
    val extra = project.extensions.getByType(ExtraPropertiesExtension::class.java)

    // Étape 3 : Définir la propriété requise pour ce test
    extra.set(&amp;quot;site_config_path&amp;quot;, &amp;quot;src/jbake/settings/site.yml&amp;quot;)

    // Étape 4 : Vérifier que la propriété est bien injectée
    assertTrue(project.hasProperty(&amp;quot;site_config_path&amp;quot;))

    // Étape 5 : Appliquer le plugin qui pourra maintenant accéder à la propriété
    project.plugins.apply(&amp;quot;jbake.ghpages&amp;quot;)

    // Étape 6 : Exécuter la tâche et vérifier son comportement
    val task: Task = project.tasks.findByName(&amp;quot;initialize&amp;quot;)
        .apply(::assertNotNull)!!

    // Étape 7 : Exécuter les actions de la tâche
    task.actions.forEach { it.execute(task) }

    // Étape 8 : Assertions finales
    assertEquals(
        &amp;quot;src/jbake/settings/site.yml&amp;quot;,
        project.properties[&amp;quot;site_config_path&amp;quot;],
        &amp;quot;La propriété devrait être accessible dans le projet&amp;quot;
    )
}&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_ステップ4ソリューションフロー図&amp;quot;&amp;gt;ステップ4：ソリューションフロー図&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
start

:Créer ProjectBuilder;
:Obtenir ExtraPropertiesExtension;
:Injecter la propriété\nvia extra.set();

partition &amp;quot;�検証&amp;quot; {
  :Vérifier project.hasProperty();
  :Appliquer le plugin;
  :Récupérer la tâche;
}

partition &amp;quot;実行&amp;quot; {
  :Exécuter les actions\nde la tâche;
  :Le plugin lit\nproject.properties;
}

partition &amp;quot;主張&amp;quot; {
  :Vérifier la propriété\nest accessible;
  :Valider le comportement\nattendues;
}

stop
@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_ステップ_5_前後比較&amp;quot;&amp;gt;ステップ 5 : 前後比較&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
!define RECTANGLE class

package &amp;quot;前 - 課題&amp;quot; {
  RECTANGLE TestProject1 {
    + ProjectBuilder.build()
    + Pas de propriétés
  }

  RECTANGLE Plugin1 {
    + initialize()
    + ❌ project.properties[&amp;quot;サイト設定パス&amp;quot;] = null
  }

  TestProject1 --&amp;amp;gt; Plugin1 : échec

  note right of Plugin1 : Test échoue car\nla propriété n&amp;#39;existe pas
}

package &amp;quot;後 - 解決策&amp;quot; {
  RECTANGLE TestProject2 {
    + ProjectBuilder.build()
    + ExtraPropertiesExtension
  }

  RECTANGLE ExtraProps {
    + set(&amp;quot;サイト設定パス&amp;quot;, &amp;quot;...&amp;quot;)
  }

  RECTANGLE Plugin2 {
    + initialize()
    + ✅ project.properties[&amp;quot;サイト設定パス&amp;quot;] = &amp;quot;src/jbake/settings/site.yml&amp;quot;
  }

  TestProject2 --&amp;amp;gt; ExtraProps : configure
  ExtraProps --&amp;amp;gt; Plugin2 : propriété disponible

  note right of Plugin2 : Test réussit car\nla propriété est simulée
}
@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_ステップ6_複数のテストケースの管理&amp;quot;&amp;gt;ステップ6: 複数のテストケースの管理&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;異なるシナリオをテストするために、様々な構成を持つ複数のテストを作成しましょう：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;Tests multiples avec configurations différentes&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-kotlin hljs&amp;quot; data-lang=&amp;quot;kotlin&amp;quot;&amp;gt;class JbakeGhPagesPluginTest {

    @TempDir
    lateinit var testProjectDir: File

    private fun createProjectWithProperty(propertyValue: String?): Project {
        val project = ProjectBuilder.builder()
            .withProjectDir(testProjectDir)
            .build()

        // Injection conditionnelle de la propriété
        propertyValue?.let { value -&amp;amp;gt;
            val extra = project.extensions.getByType(ExtraPropertiesExtension::class.java)
            extra.set(&amp;quot;site_config_path&amp;quot;, value)
        }

        return project
    }

    @Test
    fun `should work with valid property`() {
        val project = createProjectWithProperty(&amp;quot;src/jbake/settings/site.yml&amp;quot;)
        project.plugins.apply(&amp;quot;jbake.ghpages&amp;quot;)

        val task = project.tasks.findByName(&amp;quot;initialize&amp;quot;)!!
        task.actions.forEach { it.execute(task) }

        // Assertions pour le cas normal
        assertEquals(&amp;quot;src/jbake/settings/site.yml&amp;quot;, project.properties[&amp;quot;site_config_path&amp;quot;])
    }

    @Test
    fun `should handle missing property gracefully`() {
        val project = createProjectWithProperty(null) // Pas de propriété
        project.plugins.apply(&amp;quot;jbake.ghpages&amp;quot;)

        val task = project.tasks.findByName(&amp;quot;initialize&amp;quot;)!!

        // Le plugin devrait gérer l&amp;#39;absence de propriété
        assertDoesNotThrow {
            task.actions.forEach { it.execute(task) }
        }
    }

    @Test
    fun `should handle invalid property path`() {
        val project = createProjectWithProperty(&amp;quot;invalid/path/to/config.yml&amp;quot;)
        project.plugins.apply(&amp;quot;jbake.ghpages&amp;quot;)

        val task = project.tasks.findByName(&amp;quot;initialize&amp;quot;)!!

        // Test du comportement avec un chemin invalide
        assertThrows&amp;amp;lt;FileNotFoundException&amp;amp;gt; {
            task.actions.forEach { it.execute(task) }
        }
    }
}&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_ソリューションの最終アーキテクチャ&amp;quot;&amp;gt;ソリューションの最終アーキテクチャ&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
!define RECTANGLE class

package &amp;quot;テスト環境&amp;quot; {
  RECTANGLE TestClass {
    + createProjectWithProperty()
    + testValidProperty()
    + testMissingProperty()
    + testInvalidProperty()
  }

  RECTANGLE ProjectBuilder {
    + builder()
    + withProjectDir()
    + build()
  }

  RECTANGLE TestProject {
    + extensions
    + properties
    + plugins
    + tasks
  }

  RECTANGLE ExtraPropertiesExtension {
    + set(key, value)
    + get(key)
    + has(key)
  }

  RECTANGLE JbakePlugin {
    + apply(project)
    + createInitializeTask()
    + readSiteConfigPath()
  }
}

TestClass --&amp;amp;gt; ProjectBuilder : utilise
ProjectBuilder --&amp;amp;gt; TestProject : crée
TestProject --&amp;amp;gt; ExtraPropertiesExtension : contient
TestClass --&amp;amp;gt; ExtraPropertiesExtension : configure
ExtraPropertiesExtension --&amp;amp;gt; TestProject : synchronise properties
TestProject --&amp;amp;gt; JbakePlugin : applique
JbakePlugin --&amp;amp;gt; TestProject : lit properties

note right of ExtraPropertiesExtension : Point de contrôle\npour l&amp;#39;injection
note bottom of TestProject : Environnement\ncontrôlé et isolé
@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_このアプローチの利点&amp;quot;&amp;gt;このアプローチの利点&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;完全な隔離&amp;lt;/strong&amp;gt;: テストは外部ファイルに依存しません。これは自立しており、任意の環境（ローカル、CI/CD など）で信頼性高く実行できます。&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;明瞭さと意図&amp;lt;/strong&amp;gt;テストは、実行に必要な前提条件を明示的に宣言します。テストを読む人は誰でも、すぐにプラグインがプロパティを必要とすることがわかります。`site_config_path`動作するために。&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;保守性&amp;lt;/strong&amp;gt;: プロパティの名前が変更された場合、テストの設定ファイルを操作することなく、テスト内の1か所だけを更新すればよい。&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;柔軟性&amp;lt;/strong&amp;gt;各テストで注入されたプロパティの値を単純に変更するだけで、さまざまなシナリオをテストすることが容易になります（有効な値、無効な値、存在しない値など）。&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;パフォーマンス&amp;lt;/strong&amp;gt;: ファイルの読み込みは行われず、すべてメモリ内で行われるため、テストがより高速になります。&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;再現性&amp;lt;/strong&amp;gt;テストは決定論的であり、ファイルシステムの状態に依存しないからです。&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_ベストプラクティスとアドバイス&amp;quot;&amp;gt;ベストプラクティスとアドバイス&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_ユーティリティメソッドを作成する&amp;quot;&amp;gt;ユーティリティメソッドを作成する&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;Méthode utilitaire pour la réutilisation&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-kotlin hljs&amp;quot; data-lang=&amp;quot;kotlin&amp;quot;&amp;gt;class GradleTestUtils {
    companion object {
        fun createProjectWithProperties(
            projectDir: File,
            properties: Map&amp;amp;lt;String, String&amp;amp;gt;
        ): Project {
            val project = ProjectBuilder.builder()
                .withProjectDir(projectDir)
                .build()

            val extra = project.extensions.getByType(ExtraPropertiesExtension::class.java)
            properties.forEach { (key, value) -&amp;amp;gt;
                extra.set(key, value)
            }

            return project
        }
    }
}&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_プロパティの検証&amp;quot;&amp;gt;プロパティの検証&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;Validation robuste&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-kotlin hljs&amp;quot; data-lang=&amp;quot;kotlin&amp;quot;&amp;gt;@Test
fun `should validate property injection`() {
    val project = createProjectWithProperty(&amp;quot;test-value&amp;quot;)

    // Vérifications multiples
    assertTrue(project.hasProperty(&amp;quot;site_config_path&amp;quot;))
    assertEquals(&amp;quot;test-value&amp;quot;, project.property(&amp;quot;site_config_path&amp;quot;))
    assertNotNull(project.properties[&amp;quot;site_config_path&amp;quot;])

    // Vérification que la propriété est accessible par le plugin
    project.plugins.apply(&amp;quot;jbake.ghpages&amp;quot;)
    // ... reste du test
}&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_結論&amp;quot;&amp;gt;結論&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;ユニットテスト環境で設定ファイルを読み込ませるのに苦労する代わりに、ベストプラクティスは必要な状態をシミュレートすることです。使用する`ExtraPropertiesExtension`Gradleのプロパティをプログラムで設定することは、効果的かつ信頼性の高いプラグインのユニットテストを実現するための最もシンプルで堅牢な方法です。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;この技術は、外部依存の問題を単純な依存注入に変換し、テスト駆動開発（TDD）の哲学の核となる部分に組み込む。これにより、テスト環境に対する完全な制御が可能になり、品質の高い単体テストに必要な分離を維持しつつ、効果的なテストを実現できる。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;本記事に掲載されている図と例は、このアプローチが段階的かつ体系的にどのように実装できるかを示しており、Gradle プラグインのための堅牢で保守性の高いテストスイートを作成することを可能にします。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;</description>
        </item><item>
            <title>Optimiser la Gestion des Tâches Gradle avec Kotlin DSL et buildSrc</title>
            <link >https://cheroliv.com/blog/2025/0079_gradle_tasks_tests_report_post.html</link>
            <pubDate>Fri, 11 Jul 2025 00:00:00 +0000</pubDate>
            <guid isPermaLink="false">blog/2025/0079_gradle_tasks_tests_report_post.html</guid>
            <description>&amp;lt;div id=&amp;quot;toc&amp;quot; class=&amp;quot;toc&amp;quot;&amp;gt;
&amp;lt;div id=&amp;quot;toctitle&amp;quot;&amp;gt;Sommaire&amp;lt;/div&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel1&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_centraliser_les_configurations_avec_allprojects_et_subprojects&amp;quot;&amp;gt;Centraliser les Configurations avec &amp;lt;code&amp;gt;allprojects&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;subprojects&amp;lt;/code&amp;gt;&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_sourceplantuml&amp;quot;&amp;gt;[source,plantuml]&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_enduml&amp;quot;&amp;gt;@enduml&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_sourcekotlin&amp;quot;&amp;gt;[source,kotlin]&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div id=&amp;quot;preamble&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;L&amp;amp;#8217;automatisation des tâches de build est cruciale pour tout projet logiciel, et Gradle, avec son DSL Kotlin, offre une flexibilité exceptionnelle. Au cours de notre conversation, nous avons exploré comment centraliser et réutiliser la logique de build, notamment pour les rapports de tests, en tirant parti de &amp;lt;strong&amp;gt;allprojects&amp;lt;/strong&amp;gt;, &amp;lt;strong&amp;gt;buildSrc&amp;lt;/strong&amp;gt;, et des tâches personnalisées en Kotlin.&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_centraliser_les_configurations_avec_allprojects_et_subprojects&amp;quot;&amp;gt;Centraliser les Configurations avec &amp;lt;code&amp;gt;allprojects&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;subprojects&amp;lt;/code&amp;gt;&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;Les blocs &amp;lt;code&amp;gt;allprojects&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;subprojects&amp;lt;/code&amp;gt; dans votre &amp;lt;code&amp;gt;build.gradle.kts&amp;lt;/code&amp;gt; racine sont fondamentaux pour appliquer des configurations communes à travers votre projet multi-modules.&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;code&amp;gt;allprojects { &amp;amp;#8230;&amp;amp;#8203; }&amp;lt;/code&amp;gt;: Applique la configuration au &amp;lt;strong&amp;gt;projet racine et à tous ses sous-projets&amp;lt;/strong&amp;gt;. Idéal pour définir un &amp;lt;code&amp;gt;group&amp;lt;/code&amp;gt;, une &amp;lt;code&amp;gt;version&amp;lt;/code&amp;gt;, ou des &amp;lt;code&amp;gt;repositories&amp;lt;/code&amp;gt; communs. * &amp;lt;code&amp;gt;subprojects { &amp;amp;#8230;&amp;amp;#8203; }&amp;lt;/code&amp;gt;: Applique la configuration &amp;lt;strong&amp;gt;uniquement aux sous-projets&amp;lt;/strong&amp;gt;, excluant le projet racine. Parfait pour appliquer des plugins spécifiques aux modules (comme &amp;lt;code&amp;gt;java&amp;lt;/code&amp;gt; ou &amp;lt;code&amp;gt;kotlin-jvm&amp;lt;/code&amp;gt;) ou des dépendances communes à vos bibliothèques.&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;Voici un exemple illustratif :&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-kotlin hljs&amp;quot; data-lang=&amp;quot;kotlin&amp;quot;&amp;gt;// build.gradle.kts (projet racine)
plugins {
    base // Appliqué au projet racine
}

allprojects {
    group = &amp;quot;com.example&amp;quot;
    version = &amp;quot;1.0.0&amp;quot;

    repositories {
        mavenCentral()
    }

    tasks.withType&amp;amp;lt;org.gradle.api.tasks.testing.Test&amp;amp;gt; {
        useJUnitPlatform() // Configuration commune des tests pour tous les projets
    }
}

subprojects {
    apply(plugin = &amp;quot;java&amp;quot;)
    apply(plugin = &amp;quot;org.jetbrains.kotlin.jvm&amp;quot;)

    dependencies {
        implementation(&amp;quot;org.jetbrains.kotlin:kotlin-stdlib-jdk8&amp;quot;)
    }

}&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;\== &amp;lt;code&amp;gt;buildSrc&amp;lt;/code&amp;gt;: Le Couteau Suisse de la Logique de Build&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;Lorsque la logique de vos tâches devient complexe ou doit être réutilisée, &amp;lt;strong&amp;gt;buildSrc&amp;lt;/strong&amp;gt; est la solution privilégiée. C&amp;amp;#8217;est un module Gradle spécial qui est compilé avant les scripts de build principaux, rendant ses classes disponibles sur le classpath de l&amp;amp;#8217;ensemble de votre build.&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;\=== Pourquoi utiliser &amp;lt;code&amp;gt;buildSrc&amp;lt;/code&amp;gt; pour les Tâches ?&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;Réutilisabilité&amp;lt;/strong&amp;gt;: Une tâche définie dans &amp;lt;code&amp;gt;buildSrc&amp;lt;/code&amp;gt; peut être appliquée à n&amp;amp;#8217;importe quel projet du build.&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;Organisation&amp;lt;/strong&amp;gt;: Centralise le code de build, le rendant plus propre et maintenable.&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;Type Safety et Autocomplétion&amp;lt;/strong&amp;gt;: Le code Kotlin dans &amp;lt;code&amp;gt;buildSrc&amp;lt;/code&amp;gt; est compilé, offrant la vérification des erreurs et l&amp;amp;#8217;autocomplétion de votre IDE, améliorant l&amp;amp;#8217;expérience de développement.&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;\=== Diagramme de Flux &amp;lt;code&amp;gt;buildSrc&amp;lt;/code&amp;gt; (Code PlantUML)&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;Pour générer ce diagramme, copiez le code ci-dessous et collez-le dans un outil supportant PlantUML.&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_sourceplantuml&amp;quot;&amp;gt;[source,plantuml]&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;@startuml skinparam handwritten true skinparam monochrome true&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;rectangle &amp;quot;Gradle Build Process&amp;quot; { component &amp;quot;buildSrc&amp;quot; as BS { file &amp;quot;MyCustomTask.kt&amp;quot; as T file &amp;quot;MyConventionPlugin.kt&amp;quot; as P } component &amp;quot;Root Project&amp;quot; as RP component &amp;quot;Subproject A&amp;quot; as SA component &amp;quot;Subproject B&amp;quot; as SB }&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;T --\&amp;amp;gt; P : &amp;quot;is defined in&amp;quot; P --\&amp;amp;gt; RP : &amp;quot;is applied to&amp;quot; P --\&amp;amp;gt; SA : &amp;quot;is applied to&amp;quot; P --\&amp;amp;gt; SB : &amp;quot;is applied to&amp;quot;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;RP --|\&amp;amp;gt; SA : &amp;quot;contains&amp;quot; RP --|\&amp;amp;gt; SB : &amp;quot;contains&amp;quot;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;RP -up-\&amp;amp;gt; BS : &amp;quot;depends on (for build logic)&amp;quot; SA -up-\&amp;amp;gt; BS : &amp;quot;depends on (for build logic)&amp;quot; SB -up-\&amp;amp;gt; BS : &amp;quot;depends on (for build logic)&amp;quot;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;note right of T Classes de tâches personnalisées (ex: OpenTestReportTask) end note&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;note right of P Plugins de convention qui enregistrent les tâches end note&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_enduml&amp;quot;&amp;gt;@enduml&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;\== Création de Tâches de Rapport Abstraites&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;Pour gérer les rapports de tests, nous avons conçu une approche modulaire en utilisant une classe de tâche abstraite dans &amp;lt;code&amp;gt;buildSrc&amp;lt;/code&amp;gt;. Selon vos besoins, cette classe peut hériter de &amp;lt;code&amp;gt;DefaultTask&amp;lt;/code&amp;gt; ou de &amp;lt;code&amp;gt;Exec&amp;lt;/code&amp;gt;.&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;\=== Tâche Abstraite &amp;lt;code&amp;gt;OpenTestReportTask&amp;lt;/code&amp;gt; (héritant de &amp;lt;code&amp;gt;DefaultTask&amp;lt;/code&amp;gt;)&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;Cette approche est recommandée si vous avez besoin d&amp;amp;#8217;une logique Kotlin personnalisée qui interagit avec le système de fichiers ou d&amp;amp;#8217;autres APIs Gradle, puis lance une commande externe.&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_sourcekotlin&amp;quot;&amp;gt;[source,kotlin]&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;package com.yourpackage&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;import org.gradle.api.DefaultTask import org.gradle.api.tasks.Input import org.gradle.api.tasks.TaskAction import java.io.File&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;abstract class OpenTestReportTask : DefaultTask() {&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-none hljs&amp;quot;&amp;gt;----
----
init {
    group = &amp;quot;verification&amp;quot;
    description = &amp;quot;Opens a test report in Firefox.&amp;quot;
    dependsOn(&amp;quot;check&amp;quot;) // Assure que les rapports sont générés
}

@get:Input
abstract var reportPath: String

@TaskAction
fun openReport() {
    val separator = File.separator
    val reportFile = project.layout.projectDirectory.asFile.toPath()
        .resolve(reportPath.replace(&amp;quot;/&amp;quot;, separator))
        .toAbsolutePath()
        .toFile()

    if (!reportFile.exists()) {
        logger.warn(&amp;quot;Report file does not exist: $reportFile. Ensure &amp;#39;check&amp;#39; ran.&amp;quot;)
        return
    }

    project.exec {
        commandLine(&amp;quot;firefox&amp;quot;, &amp;quot;--new-tab&amp;quot;, reportFile.absolutePath)
    }
    logger.lifecycle(&amp;quot;Opened test report: ${reportFile.absolutePath}&amp;quot;)
}
----

## }

\=== Implémentations Concrètes

Ces classes héritent de la tâche abstraite et définissent le chemin spécifique du rapport.

## [source,kotlin]

package com.yourpackage

abstract class ReportUnitTestsTask : OpenTestReportTask() { init { description = &amp;quot;Opens the unit test report in Firefox.&amp;quot; reportPath = &amp;quot;build/reports/tests/test/index.html&amp;quot; } }

package com.yourpackage

## abstract class ReportFunctionalTestsTask : OpenTestReportTask() { init { description = &amp;quot;Opens the functional test report in Firefox.&amp;quot; reportPath = &amp;quot;build/reports/tests/functionalTest/index.html&amp;quot; } }

\=== Enregistrement des Tâches

Dans le `build.gradle.kts` de votre projet racine :

## [source,kotlin]

## tasks.register\&amp;amp;lt;com.yourpackage.ReportUnitTestsTask\&amp;amp;gt;(&amp;quot;reportTests&amp;quot;) {} tasks.register\&amp;amp;lt;com.yourpackage.ReportFunctionalTestsTask\&amp;amp;gt;(&amp;quot;reportFunctionalTests&amp;quot;) {}

\=== Diagramme UML des Tâches de Rapport (Code PlantUML)

Copiez le code ci-dessous et collez-le dans un outil supportant PlantUML.

## [source,plantuml]

@startuml skinparam handwritten true skinparam monochrome true

abstract class DefaultTask { }

abstract class Exec { \+ commandLine(args: String...) \+ exec() }

abstract class OpenTestReportTask extends DefaultTask { \+ group: String = &amp;quot;verification&amp;quot; \+ description: String \+ dependsOn(&amp;quot;check&amp;quot;) \+ abstract reportPath: String \+ openReport() : void }

abstract class AbstractJbakeExecTask extends Exec { \+ group: String = &amp;quot;verification&amp;quot; \+ description: String \+ dependsOn(&amp;quot;check&amp;quot;) \+ abstract reportRelativePath: String \+ exec() : void }

class ReportUnitTestsTask extends OpenTestReportTask { \+ reportPath: String = &amp;quot;build/reports/tests/test/index.html&amp;quot; }

class ReportFunctionalTestsTask extends OpenTestReportTask { \+ reportPath: String = &amp;quot;build/reports/tests/functionalTest/index.html&amp;quot; }

class ReportJbakeTestsTask extends AbstractJbakeExecTask { \+ reportRelativePath: String = &amp;quot;build/reports/tests/test/index.html&amp;quot; }

class ReportJbakeFunctionalTestsTask extends AbstractJbakeExecTask { \+ reportRelativePath: String = &amp;quot;build/reports/tests/functionalTest/index.html&amp;quot; }

OpenTestReportTask \&amp;amp;lt;-- ReportUnitTestsTask OpenTestReportTask \&amp;amp;lt;-- ReportFunctionalTestsTask

AbstractJbakeExecTask \&amp;amp;lt;-- ReportJbakeTestsTask AbstractJbakeExecTask \&amp;amp;lt;-- ReportJbakeFunctionalTestsTask

DefaultTask \&amp;amp;lt;|-- OpenTestReportTask Exec \&amp;amp;lt;|-- AbstractJbakeExecTask DefaultTask \&amp;amp;lt;|-- Exec

## @enduml

\== Tâche Abstraite `AbstractJbakeExecTask` (héritant de `Exec`)

Si votre tâche se résume principalement à exécuter une commande externe avec des arguments variables, hériter directement de **Exec** est plus direct.

## [source,kotlin]

package com.yourpackage

import org.gradle.api.tasks.Exec import org.gradle.api.tasks.Input import java.io.File

abstract class AbstractJbakeExecTask : Exec() {

----

init { group = &amp;quot;verification&amp;quot; description = &amp;quot;Opens a Jbake project report in Firefox.&amp;quot; dependsOn(&amp;quot;check&amp;quot;) }

@get:Input abstract var reportRelativePath: String

override fun exec() { val separator = File.separator val reportFile = project.layout.projectDirectory.asFile.toPath() .resolve(reportRelativePath.replace(&amp;quot;/&amp;quot;, separator)) .toAbsolutePath() .toFile()

if (!reportFile.exists()) { logger.warn(&amp;quot;Report file does not exist: $reportFile. Ensure &amp;#39;check&amp;#39; ran.&amp;quot;) return }

commandLine(&amp;quot;firefox&amp;quot;, &amp;quot;--new-tab&amp;quot;, reportFile.absolutePath) logger.lifecycle(&amp;quot;Attempting to open report: ${reportFile.absolutePath}&amp;quot;) super.exec() // Appelle la méthode exec() de la super-classe Exec }

## }

\=== Implémentations Concrètes pour `Exec`

## [source,kotlin]

package com.yourpackage

abstract class ReportJbakeTestsTask : AbstractJbakeExecTask() { init { description = &amp;quot;Opens the Jbake unit test report in Firefox.&amp;quot; reportRelativePath = &amp;quot;build/reports/tests/test/index.html&amp;quot; } }

package com.yourpackage

## abstract class ReportJbakeFunctionalTestsTask : AbstractJbakeExecTask() { init { description = &amp;quot;Opens the functional test report in Firefox.&amp;quot; reportRelativePath = &amp;quot;build/reports/tests/functionalTest/index.html&amp;quot; } }

\== Visibilité des Tâches `buildSrc`

Les tâches et classes que vous définissez dans **buildSrc** sont :

* **Visibles et utilisables** par tous les projets de votre build principal (racine et sous-projets). C&amp;#39;est pourquoi vous pouvez utiliser `com.yourpackage.ReportUnitTestsTask` dans `allprojects { ... }`. * **Non exécutables** directement en tant que tâches de buildSrc (par exemple, `gradle :buildSrc:reportTests` ne fonctionnerait pas si la tâche n&amp;#39;est pas enregistrée spécifiquement dans `buildSrc/build.gradle.kts`). `buildSrc` est un module de compilation, pas un module d&amp;#39;application exécutable pour ces tâches du build principal.

\=== Exécuter un rapport pour les tests de `buildSrc` lui-même

Si `buildSrc` a ses propres tests et génère des rapports, vous pouvez enregistrer une tâche de rapport directement dans `buildSrc/build.gradle.kts` :

## [source,kotlin]

plugins { `kotlin-jvm` }

repositories { mavenCentral() }

tasks.withType\&amp;amp;lt;Test\&amp;amp;gt; { useJUnitPlatform() reports.html.outputLocation.set(layout.buildDirectory.dir(&amp;quot;reports/tests&amp;quot;)) }

import com.yourpackage.ReportJbakeTestsTask // Importez votre classe de tâche

## tasks.register\&amp;amp;lt;ReportJbakeTestsTask\&amp;amp;gt;(&amp;quot;reportBuildSrcTests&amp;quot;) { // Le chemin est déjà défini dans la classe, il pointera vers les rapports de buildSrc }

Vous pourrez ensuite exécuter : `./gradlew :buildSrc:test` suivi de `./gradlew :buildSrc:reportBuildSrcTests`.

En adoptant ces pratiques, vous construirez des systèmes de build Gradle en Kotlin DSL qui sont non seulement puissants, mais aussi incroyablement modulaires, maintenables et faciles à comprendre.&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;</description>
        </item><item>
            <title>JBake と JGit を使用した設定可能な Kotlin Gradle プラグインの TDD</title>
            <link >https://cheroliv.com/blog/2025/0078_jbake_gradle_plugin_syntaxe_post.html</link>
            <pubDate>Wed, 9 Jul 2025 00:00:00 +0000</pubDate>
            <guid isPermaLink="false">blog/2025/0078_jbake_gradle_plugin_syntaxe_post.html</guid>
            <description>&amp;lt;div id=&amp;quot;toc&amp;quot; class=&amp;quot;toc&amp;quot;&amp;gt;
&amp;lt;div id=&amp;quot;toctitle&amp;quot;&amp;gt;Sommaire&amp;lt;/div&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel1&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_目的&amp;quot;&amp;gt;目的&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_宣言的設定&amp;quot;&amp;gt;宣言的設定&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_プラグインのアーキテクチャ&amp;quot;&amp;gt;プラグインのアーキテクチャ&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_dsl拡張の定義&amp;quot;&amp;gt;DSL拡張の定義&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_カスタムタスクの定義&amp;quot;&amp;gt;カスタムタスクの定義&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_gitadapterインターフェイス&amp;quot;&amp;gt;GitAdapterインターフェイス&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_jgitを使った具体的な実装&amp;quot;&amp;gt;JGitを使った具体的な実装&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_設定_dsl_kotlin&amp;quot;&amp;gt;設定 DSL Kotlin&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_mockitoを使った単体テスト&amp;quot;&amp;gt;Mockitoを使った単体テスト&amp;lt;/a&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel2&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_依存関係&amp;quot;&amp;gt;依存関係&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_gitの動作テスト&amp;quot;&amp;gt;Gitの動作テスト&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_結論&amp;quot;&amp;gt;結論&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_次のステップ&amp;quot;&amp;gt;次のステップ&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div id=&amp;quot;preamble&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;この記事は、Kotlin DSLで書かれたGradleプラグインの設計とテスト（TDD）の全体的なアプローチを紹介します。このプラグインは、*JBake*を使った静的サイトの生成と、*JGit*を介した*Gitデプロイ*を、YAML設定ファイルから自動化します。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_目的&amp;quot;&amp;gt;目的&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;Gradle プラグインを作成 :&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;Kotlin DSL で設定可能な ;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;できる :&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;JBake から静的サイトを生成する ;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;JGit を使ってリモートの Git リポジトリにデプロイする ;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;CI/CDワークフローに組み込める ;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;TDDのアプローチに従ってテスト済みです。&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_宣言的設定&amp;quot;&amp;gt;宣言的設定&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;以下は、私たちのDSLでモデリングされるYAML設定の例：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-yaml hljs&amp;quot; data-lang=&amp;quot;yaml&amp;quot;&amp;gt;bake:
  srcPath: &amp;quot;./site/jbake&amp;quot;
  destDirPath: &amp;quot;bake&amp;quot;
pushPage:
  from: &amp;quot;bake&amp;quot;
  to: &amp;quot;cvs&amp;quot;
  repo:
    name: &amp;quot;trainings&amp;quot;
    repository: &amp;quot;https://github.com/pages-content/trainings.git&amp;quot;
    credentials:
      username: &amp;quot;USERNAME&amp;quot;
      password: &amp;quot;SECRET_TOKEN&amp;quot;
  branch: &amp;quot;main&amp;quot;
  message: &amp;quot;cheroliv.com&amp;quot;&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;この構成は、Kotlin DSL で宣言可能な Gradle 拡張機能を介して表現されます。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_プラグインのアーキテクチャ&amp;quot;&amp;gt;プラグインのアーキテクチャ&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
package &amp;quot;エンジンプラグイン&amp;quot; {
class WorkspaceEngineExtension
class GenerateSiteTask
interface GitAdapter
class JGitAdapter
WorkspaceEnginePlugin --&amp;amp;gt; WorkspaceEngineExtension
WorkspaceEnginePlugin --&amp;amp;gt; GenerateSiteTask
GenerateSiteTask --&amp;amp;gt; GitAdapter
JGitAdapter ..|&amp;amp;gt; GitAdapter
}
@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_dsl拡張の定義&amp;quot;&amp;gt;DSL拡張の定義&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-kotlin hljs&amp;quot; data-lang=&amp;quot;kotlin&amp;quot;&amp;gt;open class WorkspaceEngineExtension {
    var outputDir: String = &amp;quot;build/site&amp;quot;
    var template: String = &amp;quot;freemarker&amp;quot;
    var repoUrl: String = &amp;quot;&amp;quot;
    var branch: String = &amp;quot;main&amp;quot;
    var message: String = &amp;quot;Generated by engine&amp;quot;
}&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_カスタムタスクの定義&amp;quot;&amp;gt;カスタムタスクの定義&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-kotlin hljs&amp;quot; data-lang=&amp;quot;kotlin&amp;quot;&amp;gt;abstract class GenerateSiteTask : DefaultTask() {
    lateinit var gitAdapter: GitAdapter

    @get:Input abstract val repoUrl: Property&amp;amp;lt;String&amp;amp;gt;
    @get:InputDirectory abstract val outputDir: DirectoryProperty
    @get:Input abstract val branch: Property&amp;amp;lt;String&amp;amp;gt;
    @get:Input abstract val message: Property&amp;amp;lt;String&amp;amp;gt;

    @TaskAction
    fun run() {
        val repo = gitAdapter.cloneRepository(repoUrl.get(), outputDir.get().asFile)
        gitAdapter.commitAndPush(repo, branch.get(), message.get())
    }
}&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_gitadapterインターフェイス&amp;quot;&amp;gt;GitAdapterインターフェイス&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-kotlin hljs&amp;quot; data-lang=&amp;quot;kotlin&amp;quot;&amp;gt;interface GitAdapter {
    fun cloneRepository(uri: String, directory: File): Repository
    fun commitAndPush(repo: Repository, branch: String, message: String)
}&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_jgitを使った具体的な実装&amp;quot;&amp;gt;JGitを使った具体的な実装&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-kotlin hljs&amp;quot; data-lang=&amp;quot;kotlin&amp;quot;&amp;gt;class JGitAdapter : GitAdapter {
    override fun cloneRepository(uri: String, directory: File): Repository {
        return Git.cloneRepository()
            .setURI(uri)
            .setDirectory(directory)
            .call()
            .repository
    }

    override fun commitAndPush(repo: Repository, branch: String, message: String) {
        Git(repo).use {
            it.add().addFilepattern(&amp;quot;.&amp;quot;).call()
            it.commit().setMessage(message).call()
            it.push().call()
        }
    }
}&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_設定_dsl_kotlin&amp;quot;&amp;gt;設定 DSL Kotlin&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-kotlin hljs&amp;quot; data-lang=&amp;quot;kotlin&amp;quot;&amp;gt;workspaceEngine {
    outputDir = &amp;quot;build/out&amp;quot;
    template = &amp;quot;freemarker&amp;quot;
    repoUrl = &amp;quot;https://github.com/cheroliv/trainings.git&amp;quot;
    branch = &amp;quot;main&amp;quot;
    message = &amp;quot;deploy from plugin&amp;quot;
}&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_mockitoを使った単体テスト&amp;quot;&amp;gt;Mockitoを使った単体テスト&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_依存関係&amp;quot;&amp;gt;依存関係&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-kotlin hljs&amp;quot; data-lang=&amp;quot;kotlin&amp;quot;&amp;gt;testImplementation(&amp;quot;org.mockito:mockito-core:5.12.0&amp;quot;)
testImplementation(&amp;quot;org.mockito.kotlin:mockito-kotlin:5.2.1&amp;quot;)
testImplementation(&amp;quot;org.junit.jupiter:junit-jupiter:5.10.0&amp;quot;)&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_gitの動作テスト&amp;quot;&amp;gt;Gitの動作テスト&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-kotlin hljs&amp;quot; data-lang=&amp;quot;kotlin&amp;quot;&amp;gt;class GenerateSiteTaskMockitoTest {

    @TempDir
    lateinit var tempDir: File

    @Test
    fun `task should call clone and commitAndPush`() {
        val project = ProjectBuilder.builder().build()
        val task = project.tasks.create(&amp;quot;generateSite&amp;quot;, GenerateSiteTask::class.java)

        val mockGitAdapter = mock&amp;amp;lt;GitAdapter&amp;amp;gt;()
        val mockRepo = mock&amp;amp;lt;Repository&amp;amp;gt;()

        whenever(mockGitAdapter.cloneRepository(any(), any())).thenReturn(mockRepo)

        task.gitAdapter = mockGitAdapter
        task.repoUrl.set(&amp;quot;https://github.com/cheroliv/test.git&amp;quot;)
        task.outputDir.set(project.layout.projectDirectory.dir(tempDir.name))
        task.branch.set(&amp;quot;main&amp;quot;)
        task.message.set(&amp;quot;test commit&amp;quot;)

        task.run()

        verify(mockGitAdapter).cloneRepository(eq(&amp;quot;https://github.com/cheroliv/test.git&amp;quot;), any())
        verify(mockGitAdapter).commitAndPush(eq(mockRepo), eq(&amp;quot;main&amp;quot;), eq(&amp;quot;test commit&amp;quot;))
    }
}&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
actor &amp;quot;開発者&amp;quot; as Dev
participant &amp;quot;Gradle ProjectBuilder&amp;quot; as Project
participant &amp;quot;GenerateSiteTask&amp;quot; as Task
participant &amp;quot;Gitアダプター (モック)&amp;quot; as Adapter
participant &amp;quot;JGitAdapter / Mockito&amp;quot; as Impl

Dev -&amp;amp;gt; Project : construit projet Gradle
Dev -&amp;amp;gt; Task : configure les propriétés
Task -&amp;amp;gt; Adapter : cloneRepository()
Adapter -&amp;amp;gt; Impl : simulé par Mockito
Task -&amp;amp;gt; Adapter : commitAndPush()
@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_結論&amp;quot;&amp;gt;結論&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;�責任の分離を通じて`GitAdapter`Gradle プラグインの開発において TDD を十分に適用できるようになる:&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;Gitの呼び出しは抽象的でテスト可能で、&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;DSLの設定はきれいでわかりやすい。&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;プラグインは実際の実装に依存しません。&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;このアプローチは高いテスト容易性とGitHub API、GitLabなどへの拡張性を保証します。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_次のステップ&amp;quot;&amp;gt;次のステップ&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;JBakeの生成を作为统合する`BakeAdapter`&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;統合テストを追加して`GradleRunner`&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;ファイルの自動読み込みをサポート`site.yml`SnakeYAML経由で&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;</description>
        </item><item>
            <title>AsciiDoc : 効果的なドキュメント作成のための構文を発見し、習得する</title>
            <link >https://cheroliv.com/blog/2025/0077_asciidoc_syntaxe_post.html</link>
            <pubDate>Fri, 20 Jun 2025 00:00:00 +0000</pubDate>
            <guid isPermaLink="false">blog/2025/0077_asciidoc_syntaxe_post.html</guid>
            <description>&amp;lt;div id=&amp;quot;toc&amp;quot; class=&amp;quot;toc&amp;quot;&amp;gt;
&amp;lt;div id=&amp;quot;toctitle&amp;quot;&amp;gt;Sommaire&amp;lt;/div&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel1&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_はじめに&amp;quot;&amp;gt;はじめに&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_asciidoc_とは何ですか&amp;quot;&amp;gt;AsciiDoc とは何ですか？&amp;lt;/a&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel2&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_なぜasciidocを選ぶのですか&amp;quot;&amp;gt;なぜAsciiDocを選ぶのですか？&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_ユースケース図_use_case&amp;quot;&amp;gt;ユースケース図 (Use Case)&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_マインドマップ図&amp;quot;&amp;gt;マインドマップ図&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_フローダイアグラム_フロー&amp;quot;&amp;gt;フローダイアグラム (フロー)&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_asciidocファイルの基本構造&amp;quot;&amp;gt;AsciiDocファイルの基本構造&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_基本構文&amp;quot;&amp;gt;基本構文&amp;lt;/a&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel2&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_見出しとセクション&amp;quot;&amp;gt;見出しとセクション&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_太字斜体等幅フォントのテキスト&amp;quot;&amp;gt;太字、斜体、等幅フォントのテキスト&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_箇条書きリストと番号付きリスト&amp;quot;&amp;gt;�箇条書きリストと番号付きリスト&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_リンクと画像&amp;quot;&amp;gt;リンクと画像&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_コードブロック&amp;quot;&amp;gt;コードブロック&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_絵画&amp;quot;&amp;gt;絵画&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_ノートと警告&amp;quot;&amp;gt;ノートと警告&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_属性および変数の使用&amp;quot;&amp;gt;属性および変数の使用&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_一般的なユースケース&amp;quot;&amp;gt;一般的なユースケース&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_ベストプラクティス&amp;quot;&amp;gt;ベストプラクティス&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_結論&amp;quot;&amp;gt;結論&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_さらに進むために&amp;quot;&amp;gt;さらに進むために&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div id=&amp;quot;preamble&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;読了時間： 8～12分&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_はじめに&amp;quot;&amp;gt;はじめに&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;&amp;lt;em&amp;gt;対象読者 :&amp;lt;/em&amp;gt; 開発者、技術ライター、および技術文書やリッチな記事を作成したいすべての人。&amp;lt;/div&amp;gt;
&amp;lt;p&amp;gt;AsciiDocは、構造化された技術文書、記事、本、プレゼンテーションなどを作成するために設計された軽量なマークアップ言語です。可読性、構文の豊かさ、HTML、PDF、DocBookなどさまざまなフォーマットを生成できる能力において際立ちます。この記事では、AsciiDocの基本構文を探り、すぐに使い始められるコツを紹介します。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_asciidoc_とは何ですか&amp;quot;&amp;gt;AsciiDoc とは何ですか？&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;AsciiDocはドキュメント記述言語で、Markdownに似ているがより強力です。テキスト、見出し、リスト、表、コードブロックなどを効率的に構造化することができ、さらに多くのことにも対応できます。その汎用性から、オープンソースプロジェクトのドキュメント作成、書籍の執筆、ウェブ出版において人気の選択肢となっています。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_なぜasciidocを選ぶのですか&amp;quot;&amp;gt;なぜAsciiDocを選ぶのですか？&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;olist arabic&amp;quot;&amp;gt;
&amp;lt;ol class=&amp;quot;arabic&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;読みやすく直感的な構文。&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;複雑な構造のネイティブサポート（表、注釈、警告など）。&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;マルチフォーマット生成（HTML, PDF, ePub, DocBook…。）&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;JBake や Antora などの静的サイトジェネレーターとの簡単な統合&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;属性および拡張機能を使用した高度なカスタマイズ&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ol&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_ユースケース図_use_case&amp;quot;&amp;gt;ユースケース図 (Use Case)&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;ユースケース図は、ユーザーとシステム間の主な相互作用を示すことができます。ドキュメントシステムの単純な例を以下に示します：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
:Utilisateur: --&amp;amp;gt; (Rédiger documentation)
:Utilisateur: --&amp;amp;gt; (Générer PDF)
:Utilisateur: --&amp;amp;gt; (Publier sur site web)
(Rédiger documentation) ..&amp;amp;gt; (Générer PDF) : inclut
@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_マインドマップ図&amp;quot;&amp;gt;マインドマップ図&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;マインドマップ（メンタルマップ）は、AsciiDocに関連する概念とそれらの関係を探求するのに最適です：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startmindmap
* AsciiDoc
** Syntaxe
*** Titres
*** Listes
*** Blocs de code
*** Tableaux
** Extensions
*** PlantUML
*** MathJax
** Export
*** HTML
*** PDF
*** EPUB
@endmindmap&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_フローダイアグラム_フロー&amp;quot;&amp;gt;フローダイアグラム (フロー)&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;フローダイアグラムは、AsciiDoc文書の生成プロセスを説明することができます：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
start
:Écrire fichier .adoc;
:Ajouter images et diagrammes;
if (Valider la syntaxe ?) then (oui)
:Générer HTML/PDF;
:Publier ou partager;
else (non)
:Corriger erreurs;
:back to start;
endif
stop
@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_asciidocファイルの基本構造&amp;quot;&amp;gt;AsciiDocファイルの基本構造&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;AsciiDocファイルは通常、タイトル、オプションの属性、構造化されたコンテンツの順で始まります。以下は最小限の例：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-asciidoc hljs&amp;quot; data-lang=&amp;quot;asciidoc&amp;quot;&amp;gt;= Titre Principal
Auteur
2024-09-03
:toc:
:icons: font

Votre contenu commence ici...&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_基本構文&amp;quot;&amp;gt;基本構文&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_見出しとセクション&amp;quot;&amp;gt;見出しとセクション&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;AsciiDocは複数の見出しレベルをサポートします：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-asciidoc hljs&amp;quot; data-lang=&amp;quot;asciidoc&amp;quot;&amp;gt;= Titre de niveau 1
== Titre de niveau 2
=== Titre de niveau 3
==== Titre de niveau 4&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_太字斜体等幅フォントのテキスト&amp;quot;&amp;gt;太字、斜体、等幅フォントのテキスト&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-asciidoc hljs&amp;quot; data-lang=&amp;quot;asciidoc&amp;quot;&amp;gt;*gras* _italique_ `monospace`&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_箇条書きリストと番号付きリスト&amp;quot;&amp;gt;�箇条書きリストと番号付きリスト&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-asciidoc hljs&amp;quot; data-lang=&amp;quot;asciidoc&amp;quot;&amp;gt;* Élément 1
* Élément 2

. Premier
. Deuxième
. Troisième&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_リンクと画像&amp;quot;&amp;gt;リンクと画像&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-asciidoc hljs&amp;quot; data-lang=&amp;quot;asciidoc&amp;quot;&amp;gt;Lien standard : https://asciidoc.org[AsciiDoc]
Image : image::images/logo.png[AsciiDoc Logo]&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_コードブロック&amp;quot;&amp;gt;コードブロック&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-asciidoc hljs&amp;quot; data-lang=&amp;quot;asciidoc&amp;quot;&amp;gt;[source,python]&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;def hello(): print(&amp;quot;こんにちは AsciiDoc !&amp;quot;)&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_絵画&amp;quot;&amp;gt;絵画&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-asciidoc hljs&amp;quot; data-lang=&amp;quot;asciidoc&amp;quot;&amp;gt;|===
| Colonne 1 | Colonne 2

| Valeur A
| Valeur B

| Valeur C
| Valeur D
|===&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_ノートと警告&amp;quot;&amp;gt;ノートと警告&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;AsciiDocは視覚情報ブロックを提供します：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-asciidoc hljs&amp;quot; data-lang=&amp;quot;asciidoc&amp;quot;&amp;gt;NOTE: Ceci est une note importante.
TIP: Conseil utile pour l’utilisateur.
WARNING: Attention à ce point.&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_属性および変数の使用&amp;quot;&amp;gt;属性および変数の使用&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;カスタム属性により、値を再利用したり動作を設定したりすることができます :&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-asciidoc hljs&amp;quot; data-lang=&amp;quot;asciidoc&amp;quot;&amp;gt;:project-name: AsciiDoc Explorer

Le projet s’appelle {project-name}.&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_一般的なユースケース&amp;quot;&amp;gt;一般的なユースケース&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;オープンソースプロジェクトのドキュメント (README、技術ガイド) - 書籍および電子書籍の執筆 - 静的Webサイトの自動生成（JBake、Antora） - 技術プレゼンテーション&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_ベストプラクティス&amp;quot;&amp;gt;ベストプラクティス&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;一貫した見出しと自動目次 (:toc:) を使用してください。 - アドモニションを使用して、重要なポイントに注意を引いてください。 ファイルを構造化してメンテナンスを容易にします。 - 注釈付きコードブロックを活用して、例を示してください。&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_結論&amp;quot;&amp;gt;結論&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;AsciiDocは、技術ドキュメントや構造化された記事を作成するための強力で使いやすいツールです。豊富な構文とマルチフォーマット生成を組み合わせることで、要求の厳しい開発者や執筆者にとって理想的な味方となります。次のプロジェクトでAsciiDocを試してみて、その違いを体感してください！&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_さらに進むために&amp;quot;&amp;gt;さらに進むために&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;公式ドキュメント : &amp;lt;a href=&amp;quot;https://asciidoc.org&amp;quot; class=&amp;quot;bare&amp;quot;&amp;gt;https://asciidoc.org&amp;lt;/a&amp;gt; - Asciidoctor : &amp;lt;a href=&amp;quot;https://asciidoctor.org&amp;quot; class=&amp;quot;bare&amp;quot;&amp;gt;https://asciidoctor.org&amp;lt;/a&amp;gt; - JBake と AsciiDoc: &amp;lt;a href=&amp;quot;https://jbake.org/docs/2.6.4/#asciidoc_support&amp;quot; class=&amp;quot;bare&amp;quot;&amp;gt;https://jbake.org/docs/2.6.4/#asciidoc_support&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;経験とコツをコメントで共有してください！&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;</description>
        </item><item>
            <title>Ubuntu からインターネットへローカルサービスを公開する：ポートフォワーディング完全ガイド</title>
            <link >https://cheroliv.com/blog/2025/0076_port_forwarding_post.html</link>
            <pubDate>Wed, 28 May 2025 00:00:00 +0000</pubDate>
            <guid isPermaLink="false">blog/2025/0076_port_forwarding_post.html</guid>
            <description>&amp;lt;div id=&amp;quot;toc&amp;quot; class=&amp;quot;toc&amp;quot;&amp;gt;
&amp;lt;div id=&amp;quot;toctitle&amp;quot;&amp;gt;Sommaire&amp;lt;/div&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel1&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_問題natとプライベートアドレス&amp;quot;&amp;gt;問題：NATとプライベートアドレス&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_ステップ_1_あなたのパブリック_ip_アドレスを特定する&amp;quot;&amp;gt;ステップ 1: あなたのパブリック IP アドレスを特定する&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_ステップ2ubuntuマシンのローカルipアドレスを確認する&amp;quot;&amp;gt;ステップ2：UbuntuマシンのローカルIPアドレスを確認する&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_ステップ3_ルーターでポートフォワーディングを設定する&amp;quot;&amp;gt;ステップ3: ルーターでポートフォワーディングを設定する&amp;lt;/a&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel2&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_管理インターフェースへのアクセス&amp;quot;&amp;gt;管理インターフェースへのアクセス&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_リダイレクトの設定&amp;quot;&amp;gt;リダイレクトの設定&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_ステップ_4_ubuntu_上のサービスの設定&amp;quot;&amp;gt;ステップ 4 ：Ubuntu 上のサービスの設定&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_ステップ_5_ubuntuファイアウォールの設定&amp;quot;&amp;gt;ステップ 5 : Ubuntuファイアウォールの設定&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_ステップ_6_テストと検証&amp;quot;&amp;gt;ステップ 6 : テストと検証&amp;lt;/a&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel2&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_ローカルネットワークからのテスト&amp;quot;&amp;gt;ローカルネットワークからのテスト&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_外部からのテスト&amp;quot;&amp;gt;外部からのテスト&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_ベストプラクティスとセキュリティ&amp;quot;&amp;gt;ベストプラクティスとセキュリティ&amp;lt;/a&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel2&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_基本的なセキュリティ&amp;quot;&amp;gt;基本的なセキュリティ&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_接続の監視&amp;quot;&amp;gt;接続の監視&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_リバースプロキシの使用&amp;quot;&amp;gt;リバースプロキシの使用&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_ポートフォワーディングの代替案&amp;quot;&amp;gt;ポートフォワーディングの代替案&amp;lt;/a&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel2&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_クラウドソリューション&amp;quot;&amp;gt;クラウドソリューション&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_vpsとリバースプロキシ&amp;quot;&amp;gt;VPSとリバースプロキシ&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_トラブルシューティング&amp;quot;&amp;gt;トラブルシューティング&amp;lt;/a&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel2&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_よくある問題&amp;quot;&amp;gt;よくある問題&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_ネットワークデバッグ&amp;quot;&amp;gt;ネットワークデバッグ&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_結論&amp;quot;&amp;gt;結論&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div id=&amp;quot;preamble&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;対象者 : 中級&amp;lt;/div&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;想定される前提条件&amp;lt;/strong&amp;gt; : Ubuntuの基本知識、ターミナル、基本的なネットワーク概念&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;技術的な概念&amp;lt;/strong&amp;gt; : NAT, ポートフォワーディング, ファイアウォール, リバースプロキシ&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;システムコマンド&amp;lt;/strong&amp;gt; : ターミナルの使用、ネットワーク構成&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;高度なセクション&amp;lt;/strong&amp;gt; : モニタリング, セキュリティ, クラウドの代替案&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_問題natとプライベートアドレス&amp;quot;&amp;gt;問題：NATとプライベートアドレス&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;問題 : Ubuntu マシンでウェブアプリケーションを開発していて、自宅ネットワークの外部からアクセスできるようにしたいですか？ ここがまさにぴったりの場所です！ この記事では、インターネットボックスのポートフォワーディングを設定して、ローカルサービス（例えばポート 8080）をインターネットに公開する方法を見ていきます。&amp;lt;/div&amp;gt;
&amp;lt;p&amp;gt;デフォルトでは、お使いのインターネットボックスは NAT（Network Address Translation）を使用して、ご家庭内ネットワークのすべてのデバイス間で1つのパブリック IP アドレスを共有します。お使いのローカルマシンは、インターネット上ではルーティングできないプライベート IP アドレス（192.168.x.x、10.x.x.x など）を使用します。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;Ubuntu マシンでサービスを起動すると（たとえばポート 8080 のウェブサーバーなど）、それはローカルネットワークからしかアクセスできません。インターネットからアクセスできるようにするには、ポートフォワーディングを設定する必要があります。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_ステップ_1_あなたのパブリック_ip_アドレスを特定する&amp;quot;&amp;gt;ステップ 1: あなたのパブリック IP アドレスを特定する&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;まず、インターネット接続のパブリックIPアドレスを取得しましょう：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;# Plusieurs méthodes au choix
curl ifconfig.me
curl ipecho.net/plain
wget -qO- http://ipecho.net/plain

# Ou encore
curl -s checkip.amazonaws.com&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;このIPアドレスは、インターネットユーザーがあなたのサービスにアクセスするために使用するものです。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_ステップ2ubuntuマシンのローカルipアドレスを確認する&amp;quot;&amp;gt;ステップ2：UbuntuマシンのローカルIPアドレスを確認する&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;Ubuntuマシンはローカルネットワーク上のプライベートIPアドレスを持っています。確認するには：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;# Afficher toutes les interfaces réseau
ip addr show

# Ou plus spécifiquement pour l&amp;#39;interface principale
ip route get 1.1.1.1 | awk &amp;#39;{print $7; exit}&amp;#39;

# Alternative avec hostname
hostname -I | awk &amp;#39;{print $1}&amp;#39;&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;このアドレスをメモしてください（例えば`192.168.1.100`), 設定のためにそれが必要になります。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_ステップ3_ルーターでポートフォワーディングを設定する&amp;quot;&amp;gt;ステップ3: ルーターでポートフォワーディングを設定する&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;構成はお使いのボックスのモデルによって異なりますが、原理は同じです：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_管理インターフェースへのアクセス&amp;quot;&amp;gt;管理インターフェースへのアクセス&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;ブラウザを開き、ボックスのウェブインターフェイスにアクセスしてください：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;フリーボックス&amp;lt;/strong&amp;gt;&amp;amp;lt;/think&amp;amp;gt;`192.168.1.1` ou &amp;lt;code&amp;gt;mafreebox.freebox.fr&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;Livebox Orange&amp;lt;/strong&amp;gt;:`192.168.1.1`&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;SFRボックス&amp;lt;/strong&amp;gt;&amp;amp;lt;/think&amp;amp;gt;`192.168.1.1`&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;Bbox Bouygues&amp;lt;/strong&amp;gt; : &amp;lt;code&amp;gt;192.168.1.254&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_リダイレクトの設定&amp;quot;&amp;gt;リダイレクトの設定&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;ポートフォワーディング専用のセクションを探してください（名前は変わります）:&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;ポート転送&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;NAT/PAT&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;ポートフォワーディング&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;ゲームサーバー&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;これらの設定で新しいルールを作成：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;table class=&amp;quot;tableblock frame-all grid-all stretch&amp;quot;&amp;gt;
&amp;lt;colgroup&amp;gt;
&amp;lt;col style=&amp;quot;width: 25%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 75%;&amp;quot;&amp;gt;
&amp;lt;/colgroup&amp;gt;
&amp;lt;thead&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;th class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;フィールド&amp;lt;/th&amp;gt;
&amp;lt;th class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;値&amp;lt;/th&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/thead&amp;gt;
&amp;lt;tbody&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;名前/説明&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;Ubuntuウェブサービス&amp;quot;（または他の明示的な名前）&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;外部ポート(またはパブリックポート)&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;8080&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;内部IPアドレス&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;UbuntuマシンのIPアドレス (例: 192.168.1.100)&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;内部ポート (または プライベートポート)&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;8080&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;プロトコル&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;TCP&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;状態&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;有効&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/tbody&amp;gt;
&amp;lt;/table&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_ステップ_4_ubuntu_上のサービスの設定&amp;quot;&amp;gt;ステップ 4 ：Ubuntu 上のサービスの設定&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;サービスが localhost だけではなく、すべてのインターフェイスでリッスンしていることを確認してください:&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;# ✅ Correct : écoute sur toutes les interfaces
python3 -m http.server 8080 --bind 0.0.0.0

# ❌ Incorrect : écoute seulement en local
python3 -m http.server 8080 --bind 127.0.0.1&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;サービスが正しくリスンしていることを確認する：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;# Vérifier les ports en écoute
sudo netstat -tlnp | grep :8080
# ou avec ss (plus moderne)
sudo ss -tlnp | grep :8080&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;何かのように見えるはずです`0.0.0.0:8080`そして いいえ`127.0.0.1:8080`。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_ステップ_5_ubuntuファイアウォールの設定&amp;quot;&amp;gt;ステップ 5 : Ubuntuファイアウォールの設定&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;UbuntuはデフォルトでUFW（Uncomplicated Firewall）を使用します。必要に応じて、その状態を確認し、ポートを許可してください：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;# Vérifier le statut du pare-feu
sudo ufw status

# Si le pare-feu est actif, autoriser le port 8080
sudo ufw allow 8080/tcp

# Ou plus spécifiquement pour un service web
sudo ufw allow &amp;#39;Apache&amp;#39;  # si vous utilisez Apache
sudo ufw allow &amp;#39;Nginx Full&amp;#39;  # si vous utilisez Nginx&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_ステップ_6_テストと検証&amp;quot;&amp;gt;ステップ 6 : テストと検証&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_ローカルネットワークからのテスト&amp;quot;&amp;gt;ローカルネットワークからのテスト&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;最初に、ローカルネットワークの別のマシンからアクセスをテストしてください：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;# Remplacez par l&amp;#39;IP locale de votre machine Ubuntu
curl http://192.168.1.100:8080&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_外部からのテスト&amp;quot;&amp;gt;外部からのテスト&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;今、インターネットから公開 IP アドレスを使用してテストしてください：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;# Remplacez par votre IP publique
curl http://VOTRE_IP_PUBLIQUE:8080&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;また、オンラインツールを使用することもできます：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;https://www.yougetsignal.com/tools/open-ports/&amp;quot; class=&amp;quot;bare&amp;quot;&amp;gt;https://www.yougetsignal.com/tools/open-ports/&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;https://canyouseeme.org/&amp;quot; class=&amp;quot;bare&amp;quot;&amp;gt;https://canyouseeme.org/&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_ベストプラクティスとセキュリティ&amp;quot;&amp;gt;ベストプラクティスとセキュリティ&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_基本的なセキュリティ&amp;quot;&amp;gt;基本的なセキュリティ&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;# Configurer fail2ban pour protéger contre les attaques par force brute
sudo apt update &amp;amp;amp;&amp;amp;amp; sudo apt install fail2ban

# Limiter l&amp;#39;accès avec UFW (exemple : autoriser seulement certaines IP)
sudo ufw allow from 203.0.113.0/24 to any port 8080&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_接続の監視&amp;quot;&amp;gt;接続の監視&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;# Surveiller les connexions en temps réel
sudo netstat -an | grep :8080

# Logs des connexions (selon votre application)
sudo tail -f /var/log/nginx/access.log  # pour Nginx
sudo journalctl -f -u your-service      # pour un service systemd&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_リバースプロキシの使用&amp;quot;&amp;gt;リバースプロキシの使用&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;セキュリティと柔軟性を向上させるため、Nginxなどのリバースプロキシの使用を検討してください：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-nginx hljs&amp;quot; data-lang=&amp;quot;nginx&amp;quot;&amp;gt;server {
    listen 80;
    server_name votre-domaine.com;

    location / {
        proxy_pass http://localhost:8080;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
}&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_ポートフォワーディングの代替案&amp;quot;&amp;gt;ポートフォワーディングの代替案&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_クラウドソリューション&amp;quot;&amp;gt;クラウドソリューション&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;ngrok&amp;lt;/strong&amp;gt;一時的なセキュアトンネル&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;Cloudflareトンネル&amp;lt;/strong&amp;gt;: 無料で安全なソリューション&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;serveo.net&amp;lt;/strong&amp;gt;: シンプルなSSHトンネル&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;# Exemple avec ngrok
ngrok http 8080

# Exemple avec serveo
ssh -R 80:localhost:8080 serveo.net&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_vpsとリバースプロキシ&amp;quot;&amp;gt;VPSとリバースプロキシ&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;プロフェッショナルな使用の場合、VPN経由でローカルインフラストラクチャへ向けるリバースプロキシを備えたVPSの使用を検討してください。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_トラブルシューティング&amp;quot;&amp;gt;トラブルシューティング&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_よくある問題&amp;quot;&amp;gt;よくある問題&amp;lt;/h3&amp;gt;
&amp;lt;table class=&amp;quot;tableblock frame-all grid-all stretch&amp;quot;&amp;gt;
&amp;lt;colgroup&amp;gt;
&amp;lt;col style=&amp;quot;width: 40%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 60%;&amp;quot;&amp;gt;
&amp;lt;/colgroup&amp;gt;
&amp;lt;thead&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;th class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;問題&amp;lt;/th&amp;gt;
&amp;lt;th class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;解決策&amp;lt;/th&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/thead&amp;gt;
&amp;lt;tbody&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;外部からアクセスできないサービス&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;ポートフォワーディングの設定を確認し、サービスが 0.0.0.0 でリッスンしていることを確認してください。&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;接続が拒否されました&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;サービスが起動していないか、127.0.0.1のみでリッスンしています&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;接続タイムアウト&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;ファイアウォール（ボックスまたはUbuntu）の問題またはポート転送の設定ミス&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;パブリックIPアドレスは定期的に変更されます&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;動的なDNS（DynDNS、No-IPなど）を設定してください&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/tbody&amp;gt;
&amp;lt;/table&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_ネットワークデバッグ&amp;quot;&amp;gt;ネットワークデバッグ&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;# Tester la connectivité locale
telnet localhost 8080

# Tester depuis une autre machine du réseau
telnet 192.168.1.100 8080

# Vérifier les routes réseau
ip route show

# Analyser le trafic réseau
sudo tcpdump -i any port 8080&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_結論&amp;quot;&amp;gt;結論&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;ローカルサービスをインターネットに公開するには、ポートフォワーディング、セキュリティ、監視の注意深い設定が必要です。このアプローチは開発や個人プロジェクトに最適ですが、本番環境ではより堅牢な代替手段（VPS、CDN、クラウドサービス）を検討してください。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;重要なことは常に安全を心に留めておくことです：強力なパスワードを使用し、定期的にシステムを更新し、公開されているサービスへのアクセスを監視してください。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;お気軽に、コメントでご経験やご質問を共有してください！&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;</description>
        </item><item>
            <title>Mockitoのデバッグ: Gradleプラグインテストにおける&quot;Wanted but not invoked&quot;エラーの解決</title>
            <link >https://cheroliv.com/blog/2025/0099_debugging-mockito-gradle-plugin_post.html</link>
            <pubDate>Sun, 17 Nov 2024 00:00:00 +0000</pubDate>
            <guid isPermaLink="false">blog/2025/0099_debugging-mockito-gradle-plugin_post.html</guid>
            <description>&amp;lt;div id=&amp;quot;toc&amp;quot; class=&amp;quot;toc&amp;quot;&amp;gt;
&amp;lt;div id=&amp;quot;toctitle&amp;quot;&amp;gt;Table des matières&amp;lt;/div&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel1&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_導入&amp;quot;&amp;gt;導入&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_コンテキスト_gradle_bakery_プラグイン&amp;quot;&amp;gt;コンテキスト : Gradle Bakery プラグイン&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_問題_1_悪いモックを確認する&amp;quot;&amp;gt;問題 #1 : 悪いモックを確認する&amp;lt;/a&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel2&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_診断&amp;quot;&amp;gt;�診断&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_解決策&amp;quot;&amp;gt;解決策&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_問題_2_カスケードするunfinishedstubbingexception&amp;quot;&amp;gt;問題 #2: カスケードするUnfinishedStubbingException&amp;lt;/a&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel2&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_診断_2&amp;quot;&amp;gt;�診断&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_解決策_2&amp;quot;&amp;gt;解決策&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_問題_3_設定ファイルが存在しません&amp;quot;&amp;gt;問題 #3 : 設定ファイルが存在しません&amp;lt;/a&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel2&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_診断_3&amp;quot;&amp;gt;診断&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_解決策_3&amp;quot;&amp;gt;解決策&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_問題_4_afterevaluate_と_nullpointerexception&amp;quot;&amp;gt;問題 #4 : afterEvaluate と NullPointerException&amp;lt;/a&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel2&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_診断_4&amp;quot;&amp;gt;�診断&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_解決策_4&amp;quot;&amp;gt;解決策&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_完全なソリューション&amp;quot;&amp;gt;完全なソリューション&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_学んだ教訓&amp;quot;&amp;gt;学んだ教訓&amp;lt;/a&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel2&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_正しいモックを確認する&amp;quot;&amp;gt;正しいモックを確認する&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_2_ネストされたモックを避ける&amp;quot;&amp;gt;2. ネストされたモックを避ける&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_3_評価のコールバックをモックする&amp;quot;&amp;gt;3. 評価のコールバックをモックする&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_4_パスの解決をテストする&amp;quot;&amp;gt;4. パスの解決をテストする&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_最終テストアーキテクチャ&amp;quot;&amp;gt;最終テストアーキテクチャ&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_結論&amp;quot;&amp;gt;結論&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_リソース&amp;quot;&amp;gt;リソース&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_導入&amp;quot;&amp;gt;導入&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;Gradleプラグインの開発中に&amp;lt;strong&amp;gt;ベーカリー&amp;lt;/strong&amp;gt;JBake ブログのために、見かけ上単純な問題に遭遇しました：エラーで失敗する単体テスト`Wanted but not invoked`. それが単純なバグと思われていたものが、Mockito と Kotlin を使ったモッキングの微妙さを理解するための完璧な教材ケースであることが判明しました。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;この記事では、メソッド的なデバッグの旅に皆さんをお連れします。それぞれの解決策が新たな問題を明らかにし、最終的に解決に至ります。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_コンテキスト_gradle_bakery_プラグイン&amp;quot;&amp;gt;コンテキスト : Gradle Bakery プラグイン&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;Bakery プラグインは JBake のラッパーであり、静的サイトの公開を容易にします。以下にその簡素化された構造を示します：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-kotlin hljs&amp;quot; data-lang=&amp;quot;kotlin&amp;quot;&amp;gt;class BakeryPlugin : Plugin&amp;amp;lt;Project&amp;amp;gt; {
    override fun apply(project: Project) {
        val extension = project.extensions.create(
            &amp;quot;bakery&amp;quot;,
            BakeryExtension::class.java
        )

        project.afterEvaluate {
            if (!project.layout.projectDirectory.asFile
                    .resolve(extension.configPath.get()).exists()) {
                println(&amp;quot;config file does not exists&amp;quot;)
            } else {
                // C&amp;#39;EST ICI QUE ÇA SE PASSE
                project.plugins.apply(JBakePlugin::class.java)

                val site = FileSystemManager.from(project, extension.configPath.get())
                // Configuration de JBake...
            }
        }
    }
}&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;失敗していたテストはシンプルだった：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-kotlin hljs&amp;quot; data-lang=&amp;quot;kotlin&amp;quot;&amp;gt;@Test
fun `plugin applies jbake gradle plugin`() {
    val project = createMockProject()
    val plugin = BakeryPlugin()

    plugin.apply(project)

    verify(project.plugins).apply(JBakePlugin::class.java)
}&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;エラー :&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-text hljs&amp;quot; data-lang=&amp;quot;text&amp;quot;&amp;gt;Wanted but not invoked:
pluginContainer.apply(class org.jbake.gradle.JBakePlugin);
Actually, there were zero interactions with this mock.&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_問題_1_悪いモックを確認する&amp;quot;&amp;gt;問題 #1 : 悪いモックを確認する&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_診断&amp;quot;&amp;gt;�診断&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
actor Test
participant &amp;quot;project.plugins&amp;quot; as PP
participant &amp;quot;モックプラグインコンテナ&amp;quot; as MPC
participant &amp;quot;ベーカリープラグイン&amp;quot; as BP

Test -&amp;amp;gt; Test: createMockProject()
activate Test
Test -&amp;amp;gt; MPC: create mock
Test -&amp;amp;gt; PP: doReturn mockPluginContainer
Test --&amp;amp;gt; Test: return project
deactivate Test

Test -&amp;amp;gt; BP: apply(project)
activate BP
BP -&amp;amp;gt; PP: project.plugins
PP --&amp;amp;gt; BP: returns mockPluginContainer
BP -&amp;amp;gt; MPC: apply(JBakePlugin::class.java)
deactivate BP

Test -&amp;amp;gt; PP: verify(project.plugins).apply(...)
note right
  ❌ ÉCHEC !
  Mockito vérifie &amp;quot;project.plugins&amp;quot;
  mais l&amp;#39;interaction a eu lieu sur
  &amp;quot;モックプラグインコンテナ&amp;quot;
end note
@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;問題：Mockitoは対話をトレースできません`project.plugins`なぜなら、それは実際のモックを返すだけのゲッターだから`mockPluginContainer`. 検証はモックのインスタンスに対して直接行う必要があります。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_解決策&amp;quot;&amp;gt;解決策&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;変更する`createMockProject()`2つのオブジェクトを返すために&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-kotlin hljs&amp;quot; data-lang=&amp;quot;kotlin&amp;quot;&amp;gt;private fun createMockProject(): Pair&amp;amp;lt;Project, PluginContainer&amp;amp;gt; {
    val mockPluginContainer = mock&amp;amp;lt;PluginContainer&amp;amp;gt;()
    val mockProject = mock&amp;amp;lt;Project&amp;amp;gt; {
        on { plugins } doReturn mockPluginContainer
    }
    return Pair(mockProject, mockPluginContainer)
}&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;テストを適応させる:&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-kotlin hljs&amp;quot; data-lang=&amp;quot;kotlin&amp;quot;&amp;gt;@Test
fun `plugin applies jbake gradle plugin`() {
    val (project, mockPluginContainer) = createMockProject()
    val plugin = BakeryPlugin()

    plugin.apply(project)

    // ✅ Vérification directe sur le bon mock
    verify(mockPluginContainer).apply(JBakePlugin::class.java)
}&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_問題_2_カスケードするunfinishedstubbingexception&amp;quot;&amp;gt;問題 #2: カスケードするUnfinishedStubbingException&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_診断_2&amp;quot;&amp;gt;�診断&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;最初の修正を適用した後、新しいエラーが発生しました：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-text hljs&amp;quot; data-lang=&amp;quot;text&amp;quot;&amp;gt;UnfinishedStubbingException:
Unfinished stubbing detected here
Hints:
 3. you are stubbing the behaviour of another mock inside
    before &amp;#39;thenReturn&amp;#39; instruction is completed&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;問題のあるコードは、Mockito-Kotlin の DSL 構文を使用していました：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-kotlin hljs&amp;quot; data-lang=&amp;quot;kotlin&amp;quot;&amp;gt;val mockProject = mock&amp;amp;lt;Project&amp;amp;gt; {
    on { extensions } doReturn mockExtensionContainer
    on { plugins } doReturn mockPluginContainer
    on { logger } doReturn mock()  // ❌ PROBLÈME ICI !
}&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
participant &amp;quot;モキト&amp;quot; as M
participant &amp;quot;モックビルダー&amp;quot; as MB
participant &amp;quot;インライン モック&amp;quot; as IM

M -&amp;amp;gt; MB: mock&amp;amp;lt;Project&amp;amp;gt; { ... }
activate MB
MB -&amp;amp;gt; MB: on { logger } doReturn
MB -&amp;amp;gt; IM: mock()
activate IM
note right
  ❌ Création d&amp;#39;un nouveau mock
  PENDANT le stubbing en cours !

  Mockito perd le contexte
  du stubbing parent
end note
IM --&amp;amp;gt; MB: nouveau mock
deactivate IM
MB -x M: UnfinishedStubbingException
deactivate MB
@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_解決策_2&amp;quot;&amp;gt;解決策&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;作成する&amp;lt;strong&amp;gt;すべて&amp;lt;/strong&amp;gt;スタブブロック以外のモックを、それからそれで設定する`whenever()`:&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-kotlin hljs&amp;quot; data-lang=&amp;quot;kotlin&amp;quot;&amp;gt;private fun createMockProject(): Pair&amp;amp;lt;Project, PluginContainer&amp;amp;gt; {
    // 1️⃣ Créer TOUS les mocks d&amp;#39;abord
    val mockPluginContainer = mock&amp;amp;lt;PluginContainer&amp;amp;gt;()
    val mockExtensionContainer = mock&amp;amp;lt;ExtensionContainer&amp;amp;gt;()
    val mockLogger = mock&amp;amp;lt;org.gradle.api.logging.Logger&amp;amp;gt;()
    val mockProject = mock&amp;amp;lt;Project&amp;amp;gt;()

    // 2️⃣ Configurer les mocks séparément avec whenever()
    whenever(mockProject.plugins).thenReturn(mockPluginContainer)
    whenever(mockProject.extensions).thenReturn(mockExtensionContainer)
    whenever(mockProject.logger).thenReturn(mockLogger)

    return Pair(mockProject, mockPluginContainer)
}&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;admonitionblock tip&amp;quot;&amp;gt;
&amp;lt;table&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;icon&amp;quot;&amp;gt;
&amp;lt;i class=&amp;quot;fa icon-tip&amp;quot; title=&amp;quot;Tip&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;
&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;黄金のルール&amp;lt;/strong&amp;gt;: 決して電話をかけないで`mock()`モックの設定ブロックの内部に。 まずモックを作成し、その後で設定してください。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/table&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_問題_3_設定ファイルが存在しません&amp;quot;&amp;gt;問題 #3 : 設定ファイルが存在しません&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_診断_3&amp;quot;&amp;gt;診断&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;正しいモックでも、プラグインが設定ファイルを見つけられなかったため、テストは常に失敗しました：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-kotlin hljs&amp;quot; data-lang=&amp;quot;kotlin&amp;quot;&amp;gt;// Dans BakeryPlugin.kt
if (!project.layout.projectDirectory.asFile
        .resolve(extension.configPath.get()).exists()) {
    println(&amp;quot;config file does not exists&amp;quot;)
    return@afterEvaluate  // ❌ Sort avant d&amp;#39;appliquer JBake !
}&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
participant &amp;quot;ベーカリープラグイン&amp;quot; as BP
participant &amp;quot;プロジェクトレイアウト&amp;quot; as PL
participant &amp;quot;�拡張&amp;quot; as EXT
participant &amp;quot;ファイルシステム&amp;quot; as FS

BP -&amp;amp;gt; PL: layout.projectDirectory.asFile
PL --&amp;amp;gt; BP: /some/mock/path
BP -&amp;amp;gt; EXT: extension.configPath.get()
EXT --&amp;amp;gt; BP: &amp;quot;../../site.yml&amp;quot;
BP -&amp;amp;gt; BP: resolve(&amp;quot;../../site.yml&amp;quot;)
BP -&amp;amp;gt; FS: exists() ?
FS --&amp;amp;gt; BP: false ❌
BP -&amp;amp;gt; BP: return (skip JBake)
note right
  Le plugin ne trouve pas
  le fichier et sort
  avant d&amp;#39;appliquer JBake
end note
@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_解決策_3&amp;quot;&amp;gt;解決策&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;パスの解決が機能するようにモックを設定して：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-kotlin hljs&amp;quot; data-lang=&amp;quot;kotlin&amp;quot;&amp;gt;private fun createMockProject(): Pair&amp;amp;lt;Project, PluginContainer&amp;amp;gt; {
    // ... autres mocks ...

    val configFile = File(&amp;quot;../../site.yml&amp;quot;).canonicalFile
    val projectDir = configFile.parentFile

    // Configuration cohérente des chemins
    whenever(mockConfigPathProperty.get()).thenReturn(&amp;quot;site.yml&amp;quot;)
    whenever(mockProjectDirectory.asFile).thenReturn(projectDir)

    // Maintenant : projectDir.resolve(&amp;quot;site.yml&amp;quot;) existe ! ✅
}&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
!define SUCCESS #90EE90
!define PROBLEM #FFB6C1

rectangle &amp;quot;モック設定&amp;quot; {
    card &amp;quot;projectDirectory.asFile&amp;quot; SUCCESS
    card &amp;quot;戻り値: /real/path/to/project&amp;quot; SUCCESS

    card &amp;quot;configPath.get()&amp;quot; SUCCESS
    card &amp;quot;戻り値: site.yml&amp;quot; SUCCESS

    card &amp;quot;解決()&amp;quot; SUCCESS
    card &amp;quot;/real/path/to/project/site.yml&amp;quot; SUCCESS

    card &amp;quot;存在する()&amp;quot; SUCCESS
    card &amp;quot;真 ✅&amp;quot; SUCCESS
}
@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_問題_4_afterevaluate_と_nullpointerexception&amp;quot;&amp;gt;問題 #4 : afterEvaluate と NullPointerException&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_診断_4&amp;quot;&amp;gt;�診断&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;プラグインはJBakeをブロック内で適用します`afterEvaluate`、アクセスする`buildDirectory.dir()` :&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-kotlin hljs&amp;quot; data-lang=&amp;quot;kotlin&amp;quot;&amp;gt;project.afterEvaluate {
    // ...
    project.tasks.withType(JBakeTask::class.java)
        .getByName(&amp;quot;bake&amp;quot;).apply {
            output = project.layout.buildDirectory
                .dir(site.bake.destDirPath)  // ❌ NPE ici !
                .get()
                .asFile
        }
}&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;モックの`buildDirectory.dir()&amp;lt;code&amp;gt;戻っていた`null&amp;lt;/code&amp;gt;.&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_解決策_4&amp;quot;&amp;gt;解決策&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;�嘲る`afterEvaluate`すぐに実行されるように、そして完全に設定するために`buildDirectory`：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-kotlin hljs&amp;quot; data-lang=&amp;quot;kotlin&amp;quot;&amp;gt;private fun createMockProject(): Pair&amp;amp;lt;Project, PluginContainer&amp;amp;gt; {
    // ... autres mocks ...

    val mockBuildDirectory = mock&amp;amp;lt;DirectoryProperty&amp;amp;gt;()
    val buildDir = File(projectDir, &amp;quot;build&amp;quot;)

    // Mocker dir() pour retourner un Provider valide
    whenever(mockBuildDirectory.dir(any&amp;amp;lt;String&amp;amp;gt;())).doAnswer { invocation -&amp;amp;gt;
        val path = invocation.arguments[0] as String
        val mockDirProvider = mock&amp;amp;lt;Provider&amp;amp;lt;Directory&amp;amp;gt;&amp;amp;gt;()
        val mockDir = mock&amp;amp;lt;Directory&amp;amp;gt;()

        whenever(mockDir.asFile).thenReturn(File(buildDir, path))
        whenever(mockDirProvider.get()).thenReturn(mockDir)

        mockDirProvider
    }

    // Mocker afterEvaluate pour exécution immédiate
    whenever(mockProject.afterEvaluate(any&amp;amp;lt;Action&amp;amp;lt;Project&amp;amp;gt;&amp;amp;gt;())).doAnswer { invocation -&amp;amp;gt;
        val action = invocation.arguments[0] as Action&amp;amp;lt;Project&amp;amp;gt;
        action.execute(mockProject)  // ✅ Exécution synchrone
        null
    }

    return Pair(mockProject, mockPluginContainer)
}&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
participant &amp;quot;テスト&amp;quot; as T
participant &amp;quot;ベーカリープラグイン&amp;quot; as BP
participant &amp;quot;モックプロジェクト&amp;quot; as MP
participant &amp;quot;評価後のアクション&amp;quot; as AE

T -&amp;amp;gt; BP: apply(project)
activate BP
BP -&amp;amp;gt; MP: afterEvaluate { ... }
activate MP
note right
  Mock configuré pour
  exécuter immédiatement
end note
MP -&amp;amp;gt; AE: execute(project)
activate AE
AE -&amp;amp;gt; MP: layout.buildDirectory.dir(&amp;quot;焼く&amp;quot;)
MP --&amp;amp;gt; AE: Provider&amp;amp;lt;Directory&amp;amp;gt; ✅
AE -&amp;amp;gt; MP: plugins.apply(JBakePlugin)
deactivate AE
MP --&amp;amp;gt; BP:
deactivate MP
BP --&amp;amp;gt; T:
deactivate BP

T -&amp;amp;gt; T: verify(mockPluginContainer).apply(...)
note right: ✅ SUCCÈS !
@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_完全なソリューション&amp;quot;&amp;gt;完全なソリューション&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;こちらが関数です`createMockProject()`フィナーレ、すべての問題を解決する：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-kotlin hljs&amp;quot; data-lang=&amp;quot;kotlin&amp;quot;&amp;gt;private fun createMockProject(): Pair&amp;amp;lt;Project, PluginContainer&amp;amp;gt; {
    // 1️⃣ CRÉER tous les mocks (pas de nested mocks !)
    val mockPluginContainer = mock&amp;amp;lt;PluginContainer&amp;amp;gt;()
    val mockExtensionContainer = mock&amp;amp;lt;ExtensionContainer&amp;amp;gt;()
    val mockLogger = mock&amp;amp;lt;org.gradle.api.logging.Logger&amp;amp;gt;()
    val mockTaskContainer = mock&amp;amp;lt;TaskContainer&amp;amp;gt;()
    val mockConfigPathProperty = mock&amp;amp;lt;Property&amp;amp;lt;String&amp;amp;gt;&amp;amp;gt;()
    val mockBakeryExtension = mock&amp;amp;lt;BakeryExtension&amp;amp;gt;()
    val mockProjectDirectory = mock&amp;amp;lt;Directory&amp;amp;gt;()
    val mockBuildDirectory = mock&amp;amp;lt;DirectoryProperty&amp;amp;gt;()
    val mockProjectLayout = mock&amp;amp;lt;ProjectLayout&amp;amp;gt;()
    val mockProject = mock&amp;amp;lt;Project&amp;amp;gt;()

    // 2️⃣ CONFIGURER la résolution des chemins
    val configFile = File(&amp;quot;../../site.yml&amp;quot;).canonicalFile
    val projectDir = configFile.parentFile
    val buildDir = File(projectDir, &amp;quot;build&amp;quot;)

    whenever(mockConfigPathProperty.get()).thenReturn(&amp;quot;site.yml&amp;quot;)
    whenever(mockConfigPathProperty.isPresent).thenReturn(true)
    whenever(mockBakeryExtension.configPath).thenReturn(mockConfigPathProperty)
    whenever(mockProjectDirectory.asFile).thenReturn(projectDir)

    // 3️⃣ CONFIGURER buildDirectory avec dir()
    whenever(mockBuildDirectory.dir(any&amp;amp;lt;String&amp;amp;gt;())).doAnswer { invocation -&amp;amp;gt;
        val path = invocation.arguments[0] as String
        val mockDirProvider = mock&amp;amp;lt;Provider&amp;amp;lt;Directory&amp;amp;gt;&amp;amp;gt;()
        val mockDir = mock&amp;amp;lt;Directory&amp;amp;gt;()
        whenever(mockDir.asFile).thenReturn(File(buildDir, path))
        whenever(mockDirProvider.get()).thenReturn(mockDir)
        mockDirProvider
    }

    // 4️⃣ ASSEMBLER le projet
    whenever(mockProjectLayout.projectDirectory).thenReturn(mockProjectDirectory)
    whenever(mockProjectLayout.buildDirectory).thenReturn(mockBuildDirectory)

    whenever(mockExtensionContainer.create(&amp;quot;bakery&amp;quot;, BakeryExtension::class.java))
        .thenReturn(mockBakeryExtension)
    whenever(mockExtensionContainer.getByType(BakeryExtension::class.java))
        .thenReturn(mockBakeryExtension)

    whenever(mockProject.extensions).thenReturn(mockExtensionContainer)
    whenever(mockProject.plugins).thenReturn(mockPluginContainer)
    whenever(mockProject.tasks).thenReturn(mockTaskContainer)
    whenever(mockProject.layout).thenReturn(mockProjectLayout)
    whenever(mockProject.logger).thenReturn(mockLogger)
    whenever(mockProject.projectDir).thenReturn(projectDir)

    // 5️⃣ CONFIGURER afterEvaluate pour exécution immédiate
    whenever(mockProject.afterEvaluate(any&amp;amp;lt;Action&amp;amp;lt;Project&amp;amp;gt;&amp;amp;gt;())).doAnswer { invocation -&amp;amp;gt;
        val action = invocation.arguments[0] as Action&amp;amp;lt;Project&amp;amp;gt;
        action.execute(mockProject)
        null
    }

    return Pair(mockProject, mockPluginContainer)
}&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;そして最終テストが合格する :&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-kotlin hljs&amp;quot; data-lang=&amp;quot;kotlin&amp;quot;&amp;gt;@Test
fun `plugin applies jbake gradle plugin`() {
    val (project, mockPluginContainer) = createMockProject()
    val plugin = BakeryPlugin()

    plugin.apply(project)

    verify(mockPluginContainer).apply(JBakePlugin::class.java) // ✅ SUCCÈS !
}&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_学んだ教訓&amp;quot;&amp;gt;学んだ教訓&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startmindmap
* Mocking avec Mockito
** ✅ Bonnes pratiques
*** Créer tous les mocks d&amp;#39;abord
*** Configurer avec whenever() séparément
*** Vérifier le mock exact, pas un proxy
*** Tester la résolution des chemins
** ❌ Pièges à éviter
*** mock() dans un bloc de configuration
*** Vérifier project.x au lieu de mockX
*** Ignorer les blocs afterEvaluate
*** Retourner null pour les Providers
@endmindmap&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_正しいモックを確認する&amp;quot;&amp;gt;正しいモックを確認する&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-kotlin hljs&amp;quot; data-lang=&amp;quot;kotlin&amp;quot;&amp;gt;// ❌ FAUX
verify(project.plugins).apply(JBakePlugin::class.java)

// ✅ CORRECT
val (project, mockPluginContainer) = createMockProject()
verify(mockPluginContainer).apply(JBakePlugin::class.java)&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_2_ネストされたモックを避ける&amp;quot;&amp;gt;2. ネストされたモックを避ける&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-kotlin hljs&amp;quot; data-lang=&amp;quot;kotlin&amp;quot;&amp;gt;// ❌ FAUX - UnfinishedStubbingException
val mockProject = mock&amp;amp;lt;Project&amp;amp;gt; {
    on { logger } doReturn mock()  // Nested mock creation !
}

// ✅ CORRECT - Créer séparément
val mockLogger = mock&amp;amp;lt;org.gradle.api.logging.Logger&amp;amp;gt;()
val mockProject = mock&amp;amp;lt;Project&amp;amp;gt;()
whenever(mockProject.logger).thenReturn(mockLogger)&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_3_評価のコールバックをモックする&amp;quot;&amp;gt;3. 評価のコールバックをモックする&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-kotlin hljs&amp;quot; data-lang=&amp;quot;kotlin&amp;quot;&amp;gt;// ✅ afterEvaluate doit s&amp;#39;exécuter pour les tests
whenever(mockProject.afterEvaluate(any())).doAnswer { invocation -&amp;amp;gt;
    val action = invocation.arguments[0] as Action&amp;amp;lt;Project&amp;amp;gt;
    action.execute(mockProject)
    null
}&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_4_パスの解決をテストする&amp;quot;&amp;gt;4. パスの解決をテストする&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-kotlin hljs&amp;quot; data-lang=&amp;quot;kotlin&amp;quot;&amp;gt;// Toujours vérifier que les chemins se résolvent correctement
val extension = project.extensions.getByType(BakeryExtension::class.java)
val configPath = extension.configPath.get()
val projectDir = project.layout.projectDirectory.asFile
val resolvedConfig = projectDir.resolve(configPath)

println(&amp;quot;Resolved config: ${resolvedConfig.absolutePath}&amp;quot;)
println(&amp;quot;Exists: ${resolvedConfig.exists()}&amp;quot;)&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_最終テストアーキテクチャ&amp;quot;&amp;gt;最終テストアーキテクチャ&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre&amp;gt;@startuml
package &amp;quot;テストレイヤー&amp;quot; {
    [Test Class] --&amp;amp;gt; [createMockProject()]
}

package &amp;quot;モック作成&amp;quot; {
    [createMockProject()] --&amp;amp;gt; [Create All Mocks]
    [Create All Mocks] --&amp;amp;gt; [Configure Paths]
    [Configure Paths] --&amp;amp;gt; [Configure Callbacks]
    [Configure Callbacks] --&amp;amp;gt; [Assemble Project]
}

package &amp;quot;モックオブジェクト&amp;quot; {
    [Assemble Project] --&amp;amp;gt; [Project Mock]
    [Assemble Project] --&amp;amp;gt; [PluginContainer Mock]
    [Assemble Project] --&amp;amp;gt; [Extension Mocks]
    [Assemble Project] --&amp;amp;gt; [Layout Mocks]
}

package &amp;quot;テスト中のプラグイン&amp;quot; {
    [Test Class] --&amp;amp;gt; [BakeryPlugin]
    [BakeryPlugin] --&amp;amp;gt; [Project Mock]
    [BakeryPlugin] --&amp;amp;gt; [PluginContainer Mock]
}

package &amp;quot;検証&amp;quot; {
    [Test Class] --&amp;amp;gt; [verify(mockPluginContainer)]
}
@enduml&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_結論&amp;quot;&amp;gt;結論&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;テストの単純な問題のように見えたものが、実は優れた事例研究の対象であることが明らかになりました：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;KotlinとMockitoの細かい点&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;適切なオブジェクトをモックすることの重要性&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;テストにおける非同期コールバックの管理&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;Gradleプラグインでのパス解決&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;体系的なデバッグにより、問題の各層を理解することで、堅牢で保守性の高いソリューションにたどり着くことができました。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;admonitionblock tip&amp;quot;&amp;gt;
&amp;lt;table&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;icon&amp;quot;&amp;gt;
&amp;lt;i class=&amp;quot;fa icon-tip&amp;quot; title=&amp;quot;Tip&amp;quot;&amp;gt;&amp;lt;/i&amp;gt;
&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;テストのためのアドバイス&amp;lt;/strong&amp;gt;: 「Wanted but not invoked」にMockitoで遭遇した場合、いつも自分に問いかけてください :
1. 正しいモックを確認していますか？
2. 私のすべてのモックは設定ブロックの外で作成されていますか？
3. 私のコールバックは本当に実行されますか？
4. 私のパスは正しく解決されますか？&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/table&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_リソース&amp;quot;&amp;gt;リソース&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;https://github.com/mockito/mockito-kotlin&amp;quot;&amp;gt;Mockito-Kotlin ドキュメント&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;https://docs.gradle.org/current/userguide/custom_plugins.html&amp;quot;&amp;gt;グラドルプラグイン開発ガイド&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;https://jbake.org/&amp;quot;&amp;gt;JBake 静的サイトジェネレーター&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;hr&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;em&amp;gt;同様の問題に遭遇しましたか？テストでの経験をコメントで共有してください !&amp;lt;/em&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;</description>
        </item><item>
            <title>Kotlin Arrow : Eitherモナドのナビゲーションをマスターする</title>
            <link >https://cheroliv.com/blog/2024/0075_kotlin_arrow-traverse_right_and_left_post.html</link>
            <pubDate>Tue, 24 Sep 2024 00:00:00 +0000</pubDate>
            <guid isPermaLink="false">blog/2024/0075_kotlin_arrow-traverse_right_and_left_post.html</guid>
            <description>&amp;lt;div id=&amp;quot;toc&amp;quot; class=&amp;quot;toc&amp;quot;&amp;gt;
&amp;lt;div id=&amp;quot;toctitle&amp;quot;&amp;gt;Sommaire&amp;lt;/div&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel1&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_はじめに&amp;quot;&amp;gt;はじめに&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_either_モナドとは何ですか&amp;quot;&amp;gt;Either モナドとは何ですか？&amp;lt;/a&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel2&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_なぜ_either_を使うのか&amp;quot;&amp;gt;なぜ Either を使うのか？&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_コンテキスト&amp;quot;&amp;gt;コンテキスト&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_異なるアプローチ&amp;quot;&amp;gt;�異なるアプローチ&amp;lt;/a&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel2&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_従来のwhenを使用したアプローチ&amp;quot;&amp;gt;従来の`when`を使用したアプローチ&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_fold_を使用したより簡潔なアプローチ&amp;quot;&amp;gt;fold` を使用したより簡潔なアプローチ&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_変換_map_と_mapleft&amp;quot;&amp;gt;変�換 &amp;lt;code&amp;gt;map&amp;lt;/code&amp;gt; と `mapLeft&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_getorelse_を使ったエラー処理&amp;quot;&amp;gt;getOrElse` を使ったエラー処理&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_横のアクション_onleft_と_onright&amp;quot;&amp;gt;横のアクション &amp;lt;code&amp;gt;onLeft&amp;lt;/code&amp;gt; と `onRight&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_flatmap_を使った操作のチェーン&amp;quot;&amp;gt;flatMap` を使った操作のチェーン&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_双方向変換と_bimap&amp;quot;&amp;gt;双方向変換と `bimap&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_swap_を使用した側面の反転&amp;quot;&amp;gt;swap` を使用した側面の反転&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_tap_と_tapleft_の使用&amp;quot;&amp;gt;tap` と &amp;lt;code&amp;gt;tapLeft&amp;lt;/code&amp;gt; の使用:&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_recover_の使用&amp;quot;&amp;gt;recover` の使用 :&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_実践的なユースケース&amp;quot;&amp;gt;実践的なユースケース&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_結論&amp;quot;&amp;gt;結論&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_さらに進むために&amp;quot;&amp;gt;さらに進むために&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_はじめに&amp;quot;&amp;gt;はじめに&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;&amp;lt;em&amp;gt;対象者 :&amp;lt;/em&amp;gt; 中級から上級のKotlin開発者。&amp;lt;/div&amp;gt;
&amp;lt;p&amp;gt;Kotlinにおける関数型プログラミングの世界で、Arrowライブラリはエラーと代替ケースを処理するための強力なツールを提供します。これらのツールの中で、モナド`Either`は、成功(Right)または失敗(Left)の2つの可能な状態を表現できる能力によって特徴づけられます。 しかし、これらの2つの状態を効果的にどのようにナビゲートすればよいでしょうか？ これが本記事で探求する内容です。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_either_モナドとは何ですか&amp;quot;&amp;gt;Either モナドとは何ですか？&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;モナド`Either`は、相互に排他的な2つの可能性を表すデータ構造です。KotlinとArrowでは、操作の成功と失敗のケースを処理するためにしばしば使用され、従来の例外に代わるエレガントな選択肢を提供します。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_なぜ_either_を使うのか&amp;quot;&amp;gt;なぜ Either を使うのか？&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;olist arabic&amp;quot;&amp;gt;
&amp;lt;ol class=&amp;quot;arabic&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;明示的なエラー処理：開発者に失敗ケースを考慮させる。&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;機能的な合成 : 失敗する可能性のある操作の連鎖を容易にする。&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;型安全 : エラーは型付けされており、これによりより正確に処理するのに役立ちます。&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;例外はなし：副作用と実行フローへの予期しない中断を避ける。&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ol&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_コンテキスト&amp;quot;&amp;gt;コンテキスト&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;REST APIを開発していると仮定してhttps://spring.io/projects/spring-boot/[Spring Boot,ウィンドウズ=後で読む] et &amp;lt;a href=&amp;quot;https://kotlinlang.org/&amp;quot;&amp;gt;Kotlin&amp;lt;/a&amp;gt;, ライブラリを使用してhttps://arrow-kt.io/[矢印,ウィンドウズ=後で読む]あなたは関数を持っています。`findOneUserByEmail`返す`Either&amp;amp;lt;Throwable, User&amp;amp;gt;`この結果をエレガントかつ機能的にどのように処理しますか？&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;Userクラスがあります：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-kotlin hljs&amp;quot; data-lang=&amp;quot;kotlin&amp;quot;&amp;gt;@file:Suppress(
    &amp;quot;RemoveRedundantQualifierName&amp;quot;,
    &amp;quot;MemberVisibilityCanBePrivate&amp;quot;,
    &amp;quot;SqlNoDataSourceInspection&amp;quot;
)

package webapp.users

import arrow.core.Either
import arrow.core.left
import arrow.core.right
import com.fasterxml.jackson.annotation.JsonIgnore
import com.fasterxml.jackson.databind.ObjectMapper
import jakarta.validation.constraints.NotNull
import jakarta.validation.constraints.Pattern
import jakarta.validation.constraints.Size
import org.springframework.beans.factory.getBean
import org.springframework.context.ApplicationContext
import org.springframework.data.r2dbc.core.R2dbcEntityTemplate
import org.springframework.r2dbc.core.DatabaseClient
import org.springframework.r2dbc.core.awaitOne
import org.springframework.r2dbc.core.awaitRowsUpdated
import webapp.core.property.ANONYMOUS_USER
import webapp.core.property.EMPTY_STRING
import webapp.core.utils.AppUtils.cleanField
import webapp.users.EntityModel.Companion.ID_MEMBER
import webapp.users.User.UserDao.Attributes.EMAIL_ATTR
import webapp.users.User.UserDao.Attributes.ID_ATTR
import webapp.users.User.UserDao.Attributes.LANG_KEY_ATTR
import webapp.users.User.UserDao.Attributes.LOGIN_ATTR
import webapp.users.User.UserDao.Attributes.PASSWORD_ATTR
import webapp.users.User.UserDao.Attributes.VERSION_ATTR
import webapp.users.User.UserDao.Constraints.LOGIN_REGEX
import webapp.users.User.UserDao.Fields.EMAIL_FIELD
import webapp.users.User.UserDao.Fields.ID_FIELD
import webapp.users.User.UserDao.Fields.LANG_KEY_FIELD
import webapp.users.User.UserDao.Fields.LOGIN_FIELD
import webapp.users.User.UserDao.Fields.PASSWORD_FIELD
import webapp.users.User.UserDao.Fields.VERSION_FIELD
import webapp.users.User.UserDao.Relations.INSERT
import webapp.users.security.Role
import webapp.users.security.Role.RoleDao
import webapp.users.security.UserRole.UserRoleDao
import java.util.*
import jakarta.validation.constraints.Email as EmailConstraint

data class User(
    override val id: UUID? = null,

    @field:NotNull
    @field:Pattern(regexp = LOGIN_REGEX)
    @field:Size(min = 1, max = 50)
    val login: String,

    @JsonIgnore
    @field:NotNull
    @field:Size(min = 60, max = 60)
    val password: String = EMPTY_STRING,

    @field:EmailConstraint
    @field:Size(min = 5, max = 254)
    val email: String = EMPTY_STRING,

    @JsonIgnore
    val roles: MutableSet&amp;amp;lt;Role&amp;amp;gt; = mutableSetOf(Role(ANONYMOUS_USER)),

    @field:Size(min = 2, max = 10)
    val langKey: String = EMPTY_STRING,

    @JsonIgnore
    val version: Long = -1,
) : EntityModel&amp;amp;lt;UUID&amp;amp;gt;() {

    companion object {
        @JvmStatic
        fun main(args: Array&amp;amp;lt;String&amp;amp;gt;) = println(UserDao.Relations.sqlScript)
    }

    object UserDao {
        object Constraints {
            // Regex for acceptable logins
            const val LOGIN_REGEX =
                &amp;quot;^(?&amp;amp;gt;[a-zA-Z0-9!$&amp;amp;amp;*+=?^_`{|}~.-]+@[a-zA-Z0-9-]+(?:\\.[a-zA-Z0-9-]+)*)|(?&amp;amp;gt;[_.@A-Za-z0-9-]+)$&amp;quot;
            const val PASSWORD_MIN: Int = 4
            const val PASSWORD_MAX: Int = 16
            const val IMAGE_URL_DEFAULT = &amp;quot;https://placehold.it/50x50&amp;quot;
            const val PHONE_REGEX = &amp;quot;^(\\+|00)?[1-9]\\d{0,49}\$&amp;quot;
        }

        object Members {
            const val PASSWORD_MEMBER = &amp;quot;password&amp;quot;
            const val ROLES_MEMBER = &amp;quot;roles&amp;quot;
        }

        object Fields {
            const val ID_FIELD = &amp;quot;`id`&amp;quot;
            const val LOGIN_FIELD = &amp;quot;`login`&amp;quot;
            const val PASSWORD_FIELD = &amp;quot;`password`&amp;quot;
            const val EMAIL_FIELD = &amp;quot;`email`&amp;quot;
            const val LANG_KEY_FIELD = &amp;quot;`lang_key`&amp;quot;
            const val VERSION_FIELD = &amp;quot;`version`&amp;quot;
        }

        object Attributes {
            val ID_ATTR = ID_FIELD.cleanField()
            val LOGIN_ATTR = LOGIN_FIELD.cleanField()
            val PASSWORD_ATTR = PASSWORD_FIELD.cleanField()
            val EMAIL_ATTR = EMAIL_FIELD.cleanField()
            const val LANG_KEY_ATTR = &amp;quot;langKey&amp;quot;
            val VERSION_ATTR = VERSION_FIELD.cleanField()
        }

        object Relations {
            const val TABLE_NAME = &amp;quot;`user`&amp;quot;
            const val SQL_SCRIPT = &amp;quot;&amp;quot;&amp;quot;
            CREATE TABLE IF NOT EXISTS $TABLE_NAME (
                $ID_FIELD                     UUID default random_uuid() PRIMARY KEY,
                $LOGIN_FIELD                  VARCHAR,
                $PASSWORD_FIELD               VARCHAR,
                $EMAIL_FIELD                  VARCHAR,
                $LANG_KEY_FIELD               VARCHAR,
                $VERSION_FIELD                bigint
            );
            CREATE UNIQUE INDEX IF NOT EXISTS `uniq_idx_user_login`
            ON $TABLE_NAME ($LOGIN_FIELD);
            CREATE UNIQUE INDEX IF NOT EXISTS `uniq_idx_user_email`
            ON $TABLE_NAME ($EMAIL_FIELD);
&amp;quot;&amp;quot;&amp;quot;

            @Suppress(&amp;quot;SqlDialectInspection&amp;quot;)
            const val INSERT = &amp;quot;&amp;quot;&amp;quot;
            insert into $TABLE_NAME (
                $LOGIN_FIELD, $EMAIL_FIELD,
                $PASSWORD_FIELD, $LANG_KEY_FIELD,
                $VERSION_FIELD
            ) values ( :login, :email, :password, :langKey, :version)&amp;quot;&amp;quot;&amp;quot;

            @JvmStatic
            val sqlScript: String
                get() = setOf(
                    UserDao.Relations.SQL_SCRIPT,
                    RoleDao.Relations.SQL_SCRIPT,
                    UserRoleDao.Relations.SQL_SCRIPT
                ).joinToString(&amp;quot;&amp;quot;)
                    .trimMargin()
        }

        object Dao {
            val Pair&amp;amp;lt;User, ApplicationContext&amp;amp;gt;.toJson: String
                get() = second.getBean&amp;amp;lt;ObjectMapper&amp;amp;gt;().writeValueAsString(first)

            suspend fun Pair&amp;amp;lt;User, ApplicationContext&amp;amp;gt;.save(): Either&amp;amp;lt;Throwable, Long&amp;amp;gt; = try {
                second.getBean&amp;amp;lt;R2dbcEntityTemplate&amp;amp;gt;()
                    .databaseClient
                    .sql(INSERT)
                    .bind(LOGIN_ATTR, first.login)
                    .bind(EMAIL_ATTR, first.email)
                    .bind(PASSWORD_ATTR, first.password)
                    .bind(LANG_KEY_ATTR, first.langKey)
                    .bind(VERSION_ATTR, first.version)
                    .fetch()
                    .awaitRowsUpdated()
                    .right()
            } catch (e: Throwable) {
                e.left()
            }


            suspend fun ApplicationContext.findOneUserByEmail(
                email: String
            ): Either&amp;amp;lt;Throwable, User&amp;amp;gt; = try {
                getBean&amp;amp;lt;DatabaseClient&amp;amp;gt;()
                    .sql(&amp;quot;SELECT * FROM `user` WHERE LOWER(email) = LOWER(:email)&amp;quot;)
                    .bind(&amp;quot;email&amp;quot;, email)
                    .fetch()
                    .awaitOne()
                    .let { row -&amp;amp;gt;
                        User(
                            id = row[ID_ATTR] as UUID?,
                            login = row[LOGIN_ATTR] as String,
                            password = row[PASSWORD_ATTR] as String,
                            email = row[EMAIL_ATTR] as String,
                            langKey = row[LANG_KEY_ATTR] as String,
                            version = row[VERSION_ATTR] as Long
                        )
                    }.right()
            } catch (e: Throwable) {
                e.left()
            }
        }
    }

    /** Account REST API URIs */
    object UserRestApis {
        const val API_AUTHORITY = &amp;quot;/api/authorities&amp;quot;
        const val API_USERS = &amp;quot;/api/users&amp;quot;
        const val API_SIGNUP = &amp;quot;/signup&amp;quot;
        const val API_SIGNUP_PATH = &amp;quot;$API_USERS$API_SIGNUP&amp;quot;
        const val API_ACTIVATE = &amp;quot;/activate&amp;quot;
        const val API_ACTIVATE_PATH = &amp;quot;$API_USERS$API_ACTIVATE?key=&amp;quot;
        const val API_ACTIVATE_PARAM = &amp;quot;{activationKey}&amp;quot;
        const val API_ACTIVATE_KEY = &amp;quot;key&amp;quot;
        const val API_RESET_INIT = &amp;quot;/reset-password/init&amp;quot;
        const val API_RESET_FINISH = &amp;quot;/reset-password/finish&amp;quot;
        const val API_CHANGE = &amp;quot;/change-password&amp;quot;
        const val API_CHANGE_PATH = &amp;quot;$API_USERS$API_CHANGE&amp;quot;
    }
}

// Abstract entity model with Generic ID, which can be of any type
abstract class EntityModel&amp;amp;lt;T&amp;amp;gt;(
    open val id: T? = null
) {
    companion object {
        const val ID_MEMBER = &amp;quot;id&amp;quot;
    }
}

// Generic extension function that allows the ID to be applied to any EntityModel type
inline fun &amp;amp;lt;reified T : EntityModel&amp;amp;lt;ID&amp;amp;gt;, ID&amp;amp;gt; T.withId(id: ID): T {
    // Use reflection to create a copy with the passed ID
    return this::class.constructors.first { it.parameters.any { param -&amp;amp;gt; param.name == ID_MEMBER } }
        .call(id, *this::class.constructors.first().parameters.drop(1).map { param -&amp;amp;gt;
            this::class.members.first { member -&amp;amp;gt; member.name == param.name }.call(this)
        }.toTypedArray())
}&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_異なるアプローチ&amp;quot;&amp;gt;�異なるアプローチ&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_従来のwhenを使用したアプローチ&amp;quot;&amp;gt;従来の`when`を使用したアプローチ&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-kotlin hljs&amp;quot; data-lang=&amp;quot;kotlin&amp;quot;&amp;gt;val user: User by lazy { userFactory(USER) }

val result: Either&amp;amp;lt;Throwable, User&amp;amp;gt; = context.findOneUserByEmail(user.email)

when (result) {
    is Either.Left -&amp;amp;gt; {
        val error = result.value
        println(&amp;quot;Erreur : ${error.message}&amp;quot;)
    }
    is Either.Right -&amp;amp;gt; {
        val user = result.value
        println(&amp;quot;Utilisateur trouvé : ${user.login}&amp;quot;)
    }
}&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;この方法はシンプルで読みやすいですが、Arrowの機能的な能力を十分に活用していません。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_fold_を使用したより簡潔なアプローチ&amp;quot;&amp;gt;fold` を使用したより簡潔なアプローチ&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-kotlin hljs&amp;quot; data-lang=&amp;quot;kotlin&amp;quot;&amp;gt;result.fold(
{ error -&amp;amp;gt; println(&amp;quot;Erreur : ${error.message}&amp;quot;) },
{ user -&amp;amp;gt; println(&amp;quot;Utilisateur trouvé : ${user.login}&amp;quot;) }
)&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;`fold`これにより、Left と Right の両ケースに対して簡潔かつエレガントにアクションを定義することができます。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_変換_map_と_mapleft&amp;quot;&amp;gt;変�換 &amp;lt;code&amp;gt;map&amp;lt;/code&amp;gt; と `mapLeft&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-kotlin hljs&amp;quot; data-lang=&amp;quot;kotlin&amp;quot;&amp;gt;val processedResult = result
    .map { user -&amp;amp;gt; &amp;quot;Utilisateur trouvé : ${user.login}&amp;quot; }
    .mapLeft { error -&amp;amp;gt; &amp;quot;Erreur : ${error.message}&amp;quot; }

println(processedResult.merge())&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;このアプローチは、Eitherに格納された値を変換しつつその構造を保持し、より複雑な処理チェーンに適しています。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_getorelse_を使ったエラー処理&amp;quot;&amp;gt;getOrElse` を使ったエラー処理&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-kotlin hljs&amp;quot; data-lang=&amp;quot;kotlin&amp;quot;&amp;gt;val user = result.getOrElse { error -&amp;amp;gt;
    println(&amp;quot;Erreur : ${error.message}&amp;quot;)
    User(login = &amp;quot;default&amp;quot;, email = &amp;quot;default@example.com&amp;quot;) // utilisateur par défaut
}
println(&amp;quot;Login : ${user.login}&amp;quot;)&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;`getOrElse`デフォルト値を提供することでエラー処理をエレガントに行う。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_横のアクション_onleft_と_onright&amp;quot;&amp;gt;横のアクション &amp;lt;code&amp;gt;onLeft&amp;lt;/code&amp;gt; と `onRight&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-kotlin hljs&amp;quot; data-lang=&amp;quot;kotlin&amp;quot;&amp;gt;result.onLeft { error -&amp;amp;gt; println(&amp;quot;Erreur : ${error.message}&amp;quot;) }
.onRight { user -&amp;amp;gt; println(&amp;quot;Utilisateur trouvé : ${user.login}&amp;quot;) }&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;これらのメソッドは、Either を変更せずに各側でアクションを実行でき、ロギングや軽微な副作用に最適です。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_flatmap_を使った操作のチェーン&amp;quot;&amp;gt;flatMap` を使った操作のチェーン&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-kotlin hljs&amp;quot; data-lang=&amp;quot;kotlin&amp;quot;&amp;gt;fun findUser(email: String): Either&amp;amp;lt;Throwable, User&amp;amp;gt; = // ... implémentation

fun getUserPermissions(user: User): Either&amp;amp;lt;Throwable, List&amp;amp;lt;String&amp;amp;gt;&amp;amp;gt; = // ... implémentation

val userPermissions = findUser(&amp;quot;user@example.com&amp;quot;)
    .flatMap { user -&amp;amp;gt; getUserPermissions(user) }&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;code&amp;gt;flatMap`は、自分自身が何かを返す操作を連鎖させるのに便利です`Either&amp;lt;/code&amp;gt;, これにより　を避ける`Either`ネストされた。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_双方向変換と_bimap&amp;quot;&amp;gt;双方向変換と `bimap&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-kotlin hljs&amp;quot; data-lang=&amp;quot;kotlin&amp;quot;&amp;gt;val result: Either&amp;amp;lt;Throwable, User&amp;amp;gt; = // ... obtention du résultat
val processedResult = result.bimap(
    { error -&amp;amp;gt; &amp;quot;Erreur: ${error.message}&amp;quot; },
    { user -&amp;amp;gt; &amp;quot;Utilisateur: ${user.login}&amp;quot; }
)&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;code&amp;gt;bimap&amp;lt;/code&amp;gt;� 左側と右側の両方を一度の操作で変換できる。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_swap_を使用した側面の反転&amp;quot;&amp;gt;swap` を使用した側面の反転&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-kotlin hljs&amp;quot; data-lang=&amp;quot;kotlin&amp;quot;&amp;gt;val result: Either&amp;amp;lt;Throwable, User&amp;amp;gt; = // ... obtention du résultat
val swapped = result.swap()&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;code&amp;gt;swap`これは、一方の側を逆にしたいときに便利です`Either&amp;lt;/code&amp;gt;, 例えば、ある関数のインターフェイスを別の関数に適応させるために。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_tap_と_tapleft_の使用&amp;quot;&amp;gt;tap` と &amp;lt;code&amp;gt;tapLeft&amp;lt;/code&amp;gt; の使用:&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-kotlin hljs&amp;quot; data-lang=&amp;quot;kotlin&amp;quot;&amp;gt;result.tap { user -&amp;amp;gt; println(&amp;quot;Utilisateur trouvé : ${user.login}&amp;quot;) }
.tapLeft { error -&amp;amp;gt; println(&amp;quot;Erreur : ${error.message}&amp;quot;) }&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;同様に`onLeft` et &amp;lt;code&amp;gt;onRight&amp;lt;/code&amp;gt;, ただし、これらのメソッドは元のEitherを返し、これは操作のチェーンに役立ちます。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_recover_の使用&amp;quot;&amp;gt;recover` の使用 :&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-kotlin hljs&amp;quot; data-lang=&amp;quot;kotlin&amp;quot;&amp;gt;val recoveredUser = result.recover { error -&amp;amp;gt;
    println(&amp;quot;Erreur récupérée : ${error.message}&amp;quot;)
    User(login = &amp;quot;recovered&amp;quot;, email = &amp;quot;recovered@example.com&amp;quot;)
}
println(&amp;quot;Login : ${recoveredUser.login}&amp;quot;)&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;このメソッドは、代替値を提供することで Either.Left を Either.Right に変換することができます。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_実践的なユースケース&amp;quot;&amp;gt;実践的なユースケース&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;使ってください`fold`各ケースに対する処理が必要な単純な操作の場合 - お好みください`map` et &amp;lt;code&amp;gt;mapLeft`データ変換のために、構造を変更せずに l&amp;#39;`Either&amp;lt;/code&amp;gt;。 - 選んでください`flatMap`失敗する可能性のある操作のチェーン中に - 使用してください`recover`エラー時にデフォルト値を提供するために。 - 選んでください`onLeft` et &amp;lt;code&amp;gt;onRight&amp;lt;/code&amp;gt; (ou &amp;lt;code&amp;gt;tap&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;tapLeft&amp;lt;/code&amp;gt;) ロギングなどの副作用のために - 使って`bimap`両側を一つの操作に変換するために。 - 適用して`swap`関数のインターフェイスを別の関数に合わせなければならないとき。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_結論&amp;quot;&amp;gt;結論&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;それぞれのアプローチは、使用状況に応じて利点があります。方法としては`fold`, &amp;lt;code&amp;gt;map&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;mapLeft&amp;lt;/code&amp;gt;, et `recover`特に便利です。複数の操作を連鎖させたいときや、データを関数的に変換したいときに使用できます。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;モナド`Either`d&amp;amp;#8217;Arrow は、Kotlin アプリケーションにおける成功とエラーのケースを処理する際に、卓越した柔軟性を提供します。これらのさまざまなアプローチを習得することで、より堅牢で、読みやすく、機能的なコードを記述できるようになります。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;次のプロジェクトでは、ためらわずにこれらのテクニックを探求し、KotlinとArrowを使った関数型プログラミングの最大限の活用を試みてください！&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_さらに進むために&amp;quot;&amp;gt;さらに進むために&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;Arrow 公式ドキュメント :https://arrow-kt.io/docs/apidocs/arrow-core/arrow.core/-either/[Arrow Either] - Kotlin Coroutines と Arrow :https://arrow-kt.io/docs/fx/[Arrow Fx コルーチン]&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;体�験談とお気に入りのテクニックを共有するのを忘れずに、作業する際に`Either`以下のコメントで！&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;</description>
        </item><item>
            <title>実用ガイド：Linuxでのファイル検索</title>
            <link >https://cheroliv.com/blog/2024/0074_seach_file_linux_post.html</link>
            <pubDate>Mon, 23 Sep 2024 00:00:00 +0000</pubDate>
            <guid isPermaLink="false">blog/2024/0074_seach_file_linux_post.html</guid>
            <description>&amp;lt;div id=&amp;quot;toc&amp;quot; class=&amp;quot;toc&amp;quot;&amp;gt;
&amp;lt;div id=&amp;quot;toctitle&amp;quot;&amp;gt;Sommaire&amp;lt;/div&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel1&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_序論&amp;quot;&amp;gt;序論&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_コマンドの使用_find&amp;quot;&amp;gt;コマンドの使用 `find&amp;lt;/a&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel2&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_find_用の追加オプション&amp;quot;&amp;gt;find` 用の追加オプション&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_コマンドの使用_locate&amp;quot;&amp;gt;コマンドの使用 `locate&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_コマンド_grep_を使用してファイル内のテキストを検索する&amp;quot;&amp;gt;コマンド &amp;lt;code&amp;gt;grep&amp;lt;/code&amp;gt; を使用してファイル内のテキストを検索する&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_結論&amp;quot;&amp;gt;結論&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_序論&amp;quot;&amp;gt;序論&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;問題点： ターミナルを通じてLinuxオペレーティングシステムでファイルを検索する。&amp;lt;/div&amp;gt;
&amp;lt;p&amp;gt;この記事では、Zshターミナルを使用してUbuntuでファイルを検索する方法について探ります。Zsh（Zシェル）は、柔軟性と高度な機能のために広く使用されている強力なコマンドインタプリタです。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;Ubuntuは人気のあるLinuxディストリビューションで、ファイルを検索するための複数のコマンドラインツールを提供しています。これらのコマンドの使い方を見ていきます。&amp;lt;code&amp;gt;find&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;locate&amp;lt;/code&amp;gt; et `grep`ターミナルでファイルを素早く効率的に見つける&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_コマンドの使用_find&amp;quot;&amp;gt;コマンドの使用 `find&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;コマンド`find`特定のディレクトリとそのサブディレクトリ内のファイルを検索することができます。基本的な構文は次のとおりです：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;find [chemin] -name [nom_du_fichier]&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;これは、名前が付いたファイルを探している実用的な例です。&amp;lt;code&amp;gt;example.txt`ディレクトリの中に&amp;lt;/code&amp;gt;/home`：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;find /home -name &amp;quot;example.txt&amp;quot;&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;このコマンドはすべてのサブディレクトリを巡回します`/home`ファイルが見つかった場合、フルパスを表示して。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;コマンドのオンラインマニュアル`find` : &amp;lt;a href=&amp;quot;https://man.archlinux.org/man/find.1.fr/&amp;quot;&amp;gt;man find&amp;lt;/a&amp;gt;&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_find_用の追加オプション&amp;quot;&amp;gt;find` 用の追加オプション&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;コマンド`find`とても強力で、多数のオプションがあります。いくつかの便利な例を以下に示します：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;ファイルの種類で検索&amp;lt;/strong&amp;gt;ファイルのみを検索するには`-type f`、そしてディレクトリを検索するには、&amp;lt;code&amp;gt;-type d&amp;lt;/code&amp;gt;。 - &amp;lt;strong&amp;gt;サイズで検索&amp;lt;/strong&amp;gt;また、オプションを使用してファイルのサイズに基づいてフィルタリングすることもできます`-size`. Par exemple, pour rechercher des fichiers de plus de 100 Mo, utilisez :&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;find /home -size +100M&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_コマンドの使用_locate&amp;quot;&amp;gt;コマンドの使用 `locate&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;コマンド`locate`より速い`find`それは、システム上に存在するファイルのプリインデックスされたデータベースを使用しているためです。まず、次のコマンドでこのデータベースを更新する必要があります：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;sudo updatedb&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;その後、次のようにファイルを検索できます：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;locate example.txt&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;使っていますhttps://fr.wikipedia.org/wiki/Z_Shell[zsh]とhttps://github.com/ohmyzsh/ohmyzsh/wiki[oh-my-zsh]、コマンドであることが判明した`locate`アクセスできません`zsh`しかし、以来可能です`bash`, それに対処するために, その主張`-c`コマンドの`bash`コマンドを実行できる`bash`別のタイプの端末から。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;ここで、パターンで終わるファイルを探しています`001.pdf`� ユーザーディレクトリ内&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;bash -c &amp;quot;locate ~/*001.pdf&amp;quot;&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;コマンドのオンラインマニュアル`locate`:https://man.archlinux.org/man/locate.1.fr/[man locate,windows=read-later]&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_コマンド_grep_を使用してファイル内のテキストを検索する&amp;quot;&amp;gt;コマンド &amp;lt;code&amp;gt;grep&amp;lt;/code&amp;gt; を使用してファイル内のテキストを検索する&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;特定のテキストをファイル内で検索したい場合は、使用できます。&amp;lt;code&amp;gt;grep&amp;lt;/code&amp;gt;. 例えば、すべてのファイルで「Ubuntu」という単語の出現を検索する`.txt`現在のディレクトリを使用してください：**&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;grep &amp;quot;Ubuntu&amp;quot; *.txt&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_結論&amp;quot;&amp;gt;結論&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;Ubuntu の Zsh ターミナル を 使っ た ファイル の 検索 は、いくつか の 強力な ツール を 用い る こと が できます。&amp;lt;code&amp;gt;find&amp;lt;/code&amp;gt;�柔軟で、多様なオプションを提供し、その一方で`locate`これにより、事前に構築されたデータベースを使って高速な検索が可能になります。最後に、`grep`ファイル内のテキストの出現を見つけることができます。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;これらのコマンドは、ファイル検索をより効率的にし、ニーズに合わせた完全なツールセットを提供し、それぞれのコマンドには、コマンドで表示できるマニュアルがあります。&amp;lt;code&amp;gt;man&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;</description>
        </item><item>
            <title>Linuxのメモ</title>
            <link >https://cheroliv.com/blog/2021/0030_memo_linux_post.html</link>
            <pubDate>Mon, 23 Sep 2024 00:00:00 +0000</pubDate>
            <guid isPermaLink="false">blog/2021/0030_memo_linux_post.html</guid>
            <description>&amp;lt;div id=&amp;quot;toc&amp;quot; class=&amp;quot;toc&amp;quot;&amp;gt;
&amp;lt;div id=&amp;quot;toctitle&amp;quot;&amp;gt;Sommaire&amp;lt;/div&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel1&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_キーボード&amp;quot;&amp;gt;キーボード：&amp;lt;/a&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel2&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_ctrl_キー&amp;quot;&amp;gt;&amp;lt;em&amp;gt;&amp;amp;lt;Ctrl&amp;amp;gt; キー&amp;lt;/em&amp;gt;&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_許可承認&amp;quot;&amp;gt;許可(承認)&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_ファイル検索&amp;quot;&amp;gt;ファイル検索&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_キーボード&amp;quot;&amp;gt;キーボード：&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_ctrl_キー&amp;quot;&amp;gt;&amp;lt;em&amp;gt;&amp;amp;lt;Ctrl&amp;amp;gt; キー&amp;lt;/em&amp;gt;&amp;lt;/h3&amp;gt;
&amp;lt;table class=&amp;quot;tableblock frame-all grid-all stretch&amp;quot;&amp;gt;
&amp;lt;/table&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;https://korben.info/les-raccourcis-clavier-pour-bash-terminal-linux-et-macos.html&amp;quot;&amp;gt;リンク&amp;lt;/a&amp;gt;&amp;lt;br&amp;gt;
&amp;lt;a href=&amp;quot;https://blogmotion.fr/systeme/astuces-bash-linux-16175&amp;quot;&amp;gt;別のリンク&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_許可承認&amp;quot;&amp;gt;許可(承認)&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;CHMODはファイルのパーミッションを変更するために使用されます&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;許可      コマンド&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;U   G   W rwx rwx rwx     chmod 777 filename rwx rwx r-x     chmod 775 ファイル名 rwx r-x r-x     chmod 755 ファイル名 rw- rw- r--     chmod 664 ファイル名 rw- r-- r--     chmod 644 filename&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;U = User G = グループ W = 世界&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;r = 読み取り可能 w = 書き込み可能 x = 実行可能 - = 許可なし&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;権限を見る別の方法:&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;400 所有者によって読まれた 040     グループによって読まれる 004     他の誰かによって読まれる 200     所有者が書く 020     グループで書く 誰でも書く 100     所有者によって実行 010     グループで実行 誰でも実行できる&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;組み合わせを得るには、それらを足し合わせるだけです。&amp;lt;br&amp;gt;
例えば、所有者が読む、書く、実行するために、&amp;lt;br&amp;gt;
読まれ、実行され、グループで実行され、誰でも実行できる&amp;lt;br&amp;gt;
あなたは400+200+100+040+010+001を足して751になります。&amp;lt;br&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_ファイル検索&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;/blog/2024/0074_seach_file_linux_post.html&amp;quot;&amp;gt;ファイル検索&amp;lt;/a&amp;gt;&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;

&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;</description>
        </item><item>
            <title>Windowsホスト向けにLinuxサブシステムのポートを公開</title>
            <link >https://cheroliv.com/blog/2024/0072_Exposer_un_port_linux_subsystem_post.adoc.html</link>
            <pubDate>Thu, 1 Feb 2024 00:00:00 +0000</pubDate>
            <guid isPermaLink="false">blog/2024/0072_Exposer_un_port_linux_subsystem_post.adoc.html</guid>
            <description></description>
        </item><item>
            <title>Pandocをインストール</title>
            <link >https://cheroliv.com/blog/2024/0070_installer_pandoc_post.html</link>
            <pubDate>Tue, 30 Jan 2024 00:00:00 +0000</pubDate>
            <guid isPermaLink="false">blog/2024/0070_installer_pandoc_post.html</guid>
            <description>&amp;lt;div id=&amp;quot;preamble&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;&amp;lt;em&amp;gt;読了時間 : 3 min&amp;lt;/em&amp;gt; Pandoc はユニバーサルなドキュメント変換ツール&amp;lt;/div&amp;gt;
&amp;lt;p&amp;gt;Pandocはオープンソースのテキスト処理ソフトウェアであり、異なるフォーマット間でドキュメントを変換するために使用できます。 Pandocをインストールする方法はいくつかあります。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_ダウンロードページからのインストール&amp;quot;&amp;gt;ダウンロードページからのインストール&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;Pandocをダウンロードページからインストールするには、次の手順に従ってください。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;olist arabic&amp;quot;&amp;gt;
&amp;lt;ol class=&amp;quot;arabic&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;Pandoc のダウンロードページにアクセスしてください：https://pandoc.org/installing.html/[&amp;lt;a href=&amp;quot;https://pandoc.org/installing.html&amp;quot; class=&amp;quot;bare&amp;quot;&amp;gt;https://pandoc.org/installing.html&amp;lt;/a&amp;gt;]&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;お使いのオペレーティングシステム用のパッケージインストーラをダウンロードしてください。&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;インストーラを実行してPandocをインストールしてください。&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ol&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;ZIPファイルからのインストール&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;ZIPファイルからPandocをインストールするには、次の手順に従ってください：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;olist arabic&amp;quot;&amp;gt;
&amp;lt;ol class=&amp;quot;arabic&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;Pandocのバイナリとドキュメントを含むzipファイルをダウンロードしてください。&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;ZIPファイルを解凍してください。&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;バイナリを好きなディレクトリに移動してください。&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ol&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;Chocolateyを使用したインストール&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;Chocolatey を使用して Pandoc をインストールする手順は次のとおりです：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;olist arabic&amp;quot;&amp;gt;
&amp;lt;ol class=&amp;quot;arabic&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;コマンドプロンプトを開いてください。&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;次のコマンドを実行してください：&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ol&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-powershell hljs&amp;quot; data-lang=&amp;quot;powershell&amp;quot;&amp;gt;choco install pandoc&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;wingetを使用したインストール&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;wingetを使ってPandocをインストールする手順は次の通りです：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;olist arabic&amp;quot;&amp;gt;
&amp;lt;ol class=&amp;quot;arabic&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;コマンドプロンプトを開いてください。&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;次のコマンドを実行してください :&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ol&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-powershell hljs&amp;quot; data-lang=&amp;quot;powershell&amp;quot;&amp;gt;winget install --source winget --exact --id JohnMacFarlane.Pandoc&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;推奨事項&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;デフォルトでは、Pandoc は LaTeX を使って PDF を作成します。 LaTeXをMiKTeXを介してインストールすることをお勧めします。 オプションと共に`--pdf-engine`ただし、他のプログラムをこのタスクに指定することもできます。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;警告&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;複数のインストール方法を使用すると、Pandoc の 2 つの異なるインストールが発生する可能性があります。 代替のインストール方法に移行する前に、Pandocを正しくアンインストールすることをお勧めします。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;WSLを使用したLinuxへのインストール&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;パッケージマネージャーの pandoc バージョンが古くないか確認してください。 Pandoc は Debian、Ubuntu、Slackware、Arch、Fedora、NixOS、openSUSE、gentoo、Void のリポジトリに含まれています。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;最新バージョンを入手するために、amd64 アーキテクチャ向けのバイナリパッケージをダウンロードページで提供しています。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;この実行可能ファイルは静的にリンクされており、動的依存関係や外部データファイルへの依存もありません。 注意：スタティックリンクのため、このパッケージの pandoc バイナリは、C で書かれた外部の Lua モジュールを必要とする Lua フィルタを使用できません。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;tarball と deb インストーラーが提供されます。 debをインストールする :&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;sudo dpkg -i $DEB&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;書き込みの瞬間の例：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;wget https://github.com/jgm/pandoc/releases/download/3.1.11.1/pandoc-3.1.11.1-1-amd64.deb&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;sudo dpkg -i pandoc-3.1.11.1-1-amd64.deb&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;où `$DEB`ダウンロードされた deb へのパスです。 これにより、実行可能ファイルがインストールされます。`pandoc`そしてマニュアルページ。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;RPMベースのディストリビューションを使用している場合、当社のダウンロードページのDEBパッケージをalienを使ってインストールできるかもしれません。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;どのディストリビューションでも、 tarball からインストールできます`$DEST`(例えば、&amp;lt;code&amp;gt;/usr/local/&amp;lt;/code&amp;gt; ou &amp;lt;code&amp;gt;$HOME/.local&amp;lt;/code&amp;gt;) 行うことで :&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;tar xvzf $TGZ --strip-components 1 -C $DEST&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;où `$TGZ`ダウンロードされた zip tarball へのパスです。 Pandocのバージョンが2.0未満で、tarballを提供しないものについては、代わりに次のように試してください：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;ar p $DEB data.tar.gz | tar xvz --strip-components 2 -C $DEST&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;また、以下の手順を使用してソースからもインストールできます`Compilation à partir de la source`。 注意してください：ほとんどのディストリビューションは、パッケージリポジトリにHaskellプラットフォームを提供しています。 例えば、Debian/Ubuntuでは、それをインストールできます&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;apt-get install haskell-platform&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;デフォルトでは、Pandoc は LaTeX を使用して PDF を作成します。 パッケージマネージャを使ってTeX Liveをインストールすることをおすすめします。 (Debian/Ubuntuでは,&amp;lt;code&amp;gt;apt-get install texlive&amp;lt;/code&amp;gt;）。 オプションで`--pdf-engine`, ただし他のプログラムを指定することもできます。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;</description>
        </item><item>
            <title>JavaScript、TypeScript、および Python での kotlin.Triple の実装</title>
            <link >https://cheroliv.com/blog/2023/0069_triple_python_js_ts_post.html</link>
            <pubDate>Mon, 25 Dec 2023 00:00:00 +0000</pubDate>
            <guid isPermaLink="false">blog/2023/0069_triple_python_js_ts_post.html</guid>
            <description>&amp;lt;div id=&amp;quot;preamble&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;&amp;lt;em&amp;gt;読了時間：2分&amp;lt;/em&amp;gt; 関数型プログラミングを使用して、KotlinのTripleクラスの完全な実装をJavaScript、TypeScript、およびPythonで作成する。&amp;lt;/div&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;注:&amp;lt;/strong&amp;gt;タイプ`Maybe`, &amp;lt;code&amp;gt;Either&amp;lt;/code&amp;gt;, `Result`JavaScriptまたはTypeScriptの基本言語には含まれないので、自分たちで実装する必要があります。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_ジャバスクリプト&amp;quot;&amp;gt;ジャバスクリプト&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-javascript hljs&amp;quot; data-lang=&amp;quot;javascript&amp;quot;&amp;gt;//javascript
// Maybe type
const Maybe = (value) =&amp;amp;gt; ({
  map: (fn) =&amp;amp;gt; (value !== null &amp;amp;amp;&amp;amp;amp; value !== undefined ? Maybe(fn(value)) : Maybe(null)),
  flatMap: (fn) =&amp;amp;gt; (value !== null &amp;amp;amp;&amp;amp;amp; value !== undefined ? fn(value) : Maybe(null)),
  getOrElse: (defaultValue) =&amp;amp;gt; (value !== null &amp;amp;amp;&amp;amp;amp; value !== undefined ? value : defaultValue),
});

// Either type
const Either = {
  Left: (value) =&amp;amp;gt; ({
    map: (fn) =&amp;amp;gt; Either.Left(value),
    flatMap: (fn) =&amp;amp;gt; Either.Left(value),
    getOrElse: (defaultValue) =&amp;amp;gt; defaultValue,
    isLeft: true,
    isRight: false,
  }),
  Right: (value) =&amp;amp;gt; ({
    map: (fn) =&amp;amp;gt; Either.Right(fn(value)),
    flatMap: (fn) =&amp;amp;gt; fn(value),
    getOrElse: (defaultValue) =&amp;amp;gt; value,
    isLeft: false,
    isRight: true,
  }),
};

// Triple class
class Triple {
  constructor(a, b, c) {
    this.a = a;
    this.b = b;
    this.c = c;
  }

  map(fn) {
    return new Triple(fn(this.a), fn(this.b), fn(this.c));
  }

  static of(a, b, c) {
    return new Triple(a, b, c);
  }

  // Example method using Maybe and Either
  divideBy(other) {
    return Maybe(this.b)
      .flatMap((numerator) =&amp;amp;gt;
        Maybe(other)
          .flatMap((denominator) =&amp;amp;gt;
            denominator !== 0
              ? Either.Right(numerator / denominator)
              : Either.Left(&amp;#39;Division by zero&amp;#39;)
          )
      )
      .getOrElse(Either.Left(&amp;#39;Invalid input&amp;#39;));
  }
}

// Example usage
const triple = Triple.of(1, 2, 3);
const result = triple.map((x) =&amp;amp;gt; x * 2);
console.log(result); // Triple { a: 2, b: 4, c: 6 }

const divisionResult = triple.divideBy(2);
console.log(divisionResult); // Either.Right { value: 1 }

const invalidDivisionResult = triple.divideBy(0);
console.log(invalidDivisionResult); // Either.Left { value: &amp;#39;Division by zero&amp;#39; }&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_typescript&amp;quot;&amp;gt;TypeScript&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-typescript hljs&amp;quot; data-lang=&amp;quot;typescript&amp;quot;&amp;gt;//Typescript
// Maybe type
// noinspection JSAnnotator

type Maybe&amp;amp;lt;T&amp;amp;gt; = {
  map&amp;amp;lt;U&amp;amp;gt;(fn: (value: T) =&amp;amp;gt; U): Maybe&amp;amp;lt;U&amp;amp;gt;;
  flatMap&amp;amp;lt;U&amp;amp;gt;(fn: (value: T) =&amp;amp;gt; Maybe&amp;amp;lt;U&amp;amp;gt;): Maybe&amp;amp;lt;U&amp;amp;gt;;
  getOrElse(defaultValue: T): T;
};

const just = &amp;amp;lt;T&amp;amp;gt;(value: T): Maybe&amp;amp;lt;T&amp;amp;gt; =&amp;amp;gt; ({
  map: &amp;amp;lt;U&amp;amp;gt;(fn: (value: T) =&amp;amp;gt; U) =&amp;amp;gt; just(fn(value)),
  flatMap: &amp;amp;lt;U&amp;amp;gt;(fn: (value: T) =&amp;amp;gt; Maybe&amp;amp;lt;U&amp;amp;gt;) =&amp;amp;gt; fn(value),
  getOrElse: (_: T) =&amp;amp;gt; value,
});

const nothing = &amp;amp;lt;T&amp;amp;gt;(): Maybe&amp;amp;lt;T&amp;amp;gt; =&amp;amp;gt; ({
  map: &amp;amp;lt;U&amp;amp;gt;(_: (value: T) =&amp;amp;gt; U) =&amp;amp;gt; nothing&amp;amp;lt;U&amp;amp;gt;(),
  flatMap: &amp;amp;lt;U&amp;amp;gt;(_: (value: T) =&amp;amp;gt; Maybe&amp;amp;lt;U&amp;amp;gt;) =&amp;amp;gt; nothing&amp;amp;lt;U&amp;amp;gt;(),
  getOrElse: (defaultValue: T) =&amp;amp;gt; defaultValue,
});

// Either type
type Either&amp;amp;lt;L, R&amp;amp;gt; = {
  map&amp;amp;lt;U&amp;amp;gt;(fn: (value: R) =&amp;amp;gt; U): Either&amp;amp;lt;L, U&amp;amp;gt;;
  flatMap&amp;amp;lt;U&amp;amp;gt;(fn: (value: R) =&amp;amp;gt; Either&amp;amp;lt;L, U&amp;amp;gt;): Either&amp;amp;lt;L, U&amp;amp;gt;;
  getOrElse(defaultValue: R): R;
  isLeft: boolean;
  isRight: boolean;
};

const left = &amp;amp;lt;L, R&amp;amp;gt;(value: L): Either&amp;amp;lt;L, R&amp;amp;gt; =&amp;amp;gt; ({
  map: &amp;amp;lt;U&amp;amp;gt;(_: (value: R) =&amp;amp;gt; U) =&amp;amp;gt; left&amp;amp;lt;L, U&amp;amp;gt;(value),
  flatMap: &amp;amp;lt;U&amp;amp;gt;(_: (value: R) =&amp;amp;gt; Either&amp;amp;lt;L, U&amp;amp;gt;) =&amp;amp;gt; left&amp;amp;lt;L, U&amp;amp;gt;(value),
  getOrElse: (defaultValue: R) =&amp;amp;gt; defaultValue,
  isLeft: true,
  isRight: false,
});

const right = &amp;amp;lt;L, R&amp;amp;gt;(value: R): Either&amp;amp;lt;L, R&amp;amp;gt; =&amp;amp;gt; ({
  map: &amp;amp;lt;U&amp;amp;gt;(fn: (value: R) =&amp;amp;gt; U) =&amp;amp;gt; right&amp;amp;lt;L, U&amp;amp;gt;(fn(value)),
  flatMap: &amp;amp;lt;U&amp;amp;gt;(fn: (value: R) =&amp;amp;gt; Either&amp;amp;lt;L, U&amp;amp;gt;) =&amp;amp;gt; fn(value),
  getOrElse: (_: R) =&amp;amp;gt; value,
  isLeft: false,
  isRight: true,
});

// Triple class
class Triple&amp;amp;lt;T&amp;amp;gt; {
  constructor(public a: T, public b: T, public c: T) {}

  map&amp;amp;lt;U&amp;amp;gt;(fn: (value: T) =&amp;amp;gt; U): Triple&amp;amp;lt;U&amp;amp;gt; {
    return new Triple&amp;amp;lt;U&amp;amp;gt;(fn(this.a), fn(this.b), fn(this.c));
  }

  static of&amp;amp;lt;T&amp;amp;gt;(a: T, b: T, c: T): Triple&amp;amp;lt;T&amp;amp;gt; {
    return new Triple&amp;amp;lt;T&amp;amp;gt;(a, b, c);
  }

  // Example method using Maybe and Either
  divideBy(other: T): Either&amp;amp;lt;string, number&amp;amp;gt; {
    return just(this.b)
      .flatMap((numerator) =&amp;amp;gt;
        just(other)
          .flatMap((denominator) =&amp;amp;gt;
            denominator !== 0 ? right(numerator / denominator) : left(&amp;#39;Division by zero&amp;#39;)
          )
      )
      .getOrElse(left(&amp;#39;Invalid input&amp;#39;));
  }
}

// Example usage
const triple = Triple.of(1, 2, 3);
const result = triple.map((x) =&amp;amp;gt; x * 2);
console.log(result); // Triple { a: 2, b: 4, c: 6 }

const divisionResult = triple.divideBy(2);
console.log(divisionResult); // Either.Right { value: 1 }

const invalidDivisionResult = triple.divideBy(0);
console.log(invalidDivisionResult); // Either.Left { value: &amp;#39;Division by zero&amp;#39; }&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_pythonpydanticpymonad&amp;quot;&amp;gt;Python、pydantic、pymonad&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;Pythonを使用して実装を作成する`pydantic`型の検証のために`pymonad`単子に対して :&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;依存関係をインストールする :&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;pip install pydantic pymonad&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-python hljs&amp;quot; data-lang=&amp;quot;python&amp;quot;&amp;gt;from pymonad.either import Either, Left, Right
from pydantic import BaseModel, ValidationError, validator

# Définition de la classe Triple avec Pydantic
class Triple(BaseModel):
    a: int
    b: int
    c: int

    @validator(&amp;#39;b&amp;#39;)
    def validate_b(cls, b, values):
        if b == 0:
            raise ValueError(&amp;#39;Division by zero is not allowed&amp;#39;)
        return b

    # Méthode utilisant Either pour la gestion des erreurs
    def divide_by(self, other):
        def division(numerator, denominator):
            return Right(numerator / denominator)

        def handle_error(error):
            return Left(str(error))

        return Either(lambda: division(self.b, other)).or_else(handle_error)

# Exemple d&amp;#39;utilisation
try:
    triple = Triple(a=1, b=2, c=3)
    result = triple.divide_by(2)

    if result.is_right:
        print(f&amp;#39;Division result: {result.value}&amp;#39;)
    else:
        print(f&amp;#39;Error: {result.value}&amp;#39;)

except ValidationError as e:
    print(f&amp;#39;Validation Error: {e}&amp;#39;)
except Exception as e:
    print(f&amp;#39;An unexpected error occurred: {e}&amp;#39;)&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;この例では：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;code&amp;gt;pydantic`クラスを定義する`Triple`型付きフィールドを持つ 方法`divide_by`モナドを使用する`Either&amp;lt;/code&amp;gt; de &amp;lt;code&amp;gt;pymonad&amp;lt;/code&amp;gt;� ゼロ除算による潜在的なエラーを処理するため - カスタム検証で値が`b`� ゼロではありません。ゼロである場合、例外が発生し、そして`pymonad`この例外をキャプチャして結果を返す`Left`エラーを示している。&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;</description>
        </item><item>
            <title>Google Apps Script 入門</title>
            <link >https://cheroliv.com/blog/2023/0068_introduction_google_apps_script_post.html</link>
            <pubDate>Fri, 22 Dec 2023 00:00:00 +0000</pubDate>
            <guid isPermaLink="false">blog/2023/0068_introduction_google_apps_script_post.html</guid>
            <description>&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_目次&amp;quot;&amp;gt;目次&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;em&amp;gt;読了時間 : 30分&amp;lt;/em&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;はじめに&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;#Google Apps Scriptの基本構造&amp;quot;&amp;gt;[Google Apps Scriptの基本構造]&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;Google Apps Scriptにおける型と変数&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;#定数、変数、および文字（Google Apps Script）&amp;quot;&amp;gt;[定数、変数、および文字（Google Apps Script）]&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;Google Apps Scriptの演算と演算子&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;#Google Apps ScriptにおけるVar、Let、Const&amp;quot;&amp;gt;[Google Apps ScriptにおけるVar、Let、Const]&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;#_google_apps_script_の制御構造&amp;quot;&amp;gt;Google Apps Script の制御構造&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;#Google Apps Scriptでのループ&amp;quot;&amp;gt;[Google Apps Scriptでのループ]&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;#_google_apps_script_のオブジェクト&amp;quot;&amp;gt;Google Apps Script のオブジェクト&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;Google Apps Script の関数&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;#Google Apps Script の 設定 と スコープ&amp;quot;&amp;gt;[Google Apps Script の 設定 と スコープ]&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;#Google Apps Scriptにおけるレスト演算子とスプレッド演算子&amp;quot;&amp;gt;[Google Apps Scriptにおけるレスト演算子とスプレッド演算子]&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;Google Apps Script での分解による割り当て&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;#Google Apps Scriptでのコレクションと宣言的プログラミング&amp;quot;&amp;gt;[Google Apps Scriptでのコレクションと宣言的プログラミング]&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_はじめに&amp;quot;&amp;gt;はじめに&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;Google Apps Script (GAS) は、Google スプレッドシート、Google ドキュメント、Google フォームなどのさまざまな Google サービスに関連付けられたスクリプト開発プラットフォームです。タスクの自動化、カスタム機能の追加、Google サービスの統合を可能にします。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;このメモでは、具体的な例を用いてGoogle Apps Scriptの主要な概念について探求します。変数、ループ、関数などの概念を取り上げ、それらをGASの特定のコンテキストに適応させます。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_google_apps_script_の基本構造&amp;quot;&amp;gt;Google Apps Script の基本構造&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;始めに、Google Apps スクリプトの基本構造を見てみましょう。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-javascript hljs&amp;quot; data-lang=&amp;quot;javascript&amp;quot;&amp;gt;/**
 * Structure de base en Google Apps Script
 */
function exempleStructureGAS() {
    // Votre code ici
    Logger.log(&amp;quot;Hello, Google Apps Script!&amp;quot;);
}&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_google_apps_script_の型と変数&amp;quot;&amp;gt;Google Apps Script の型と変数&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;Google Apps Script はプログラミング言語として JavaScript を使用します。データ型と変数は標準の JavaScript と同様に機能します。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-javascript hljs&amp;quot; data-lang=&amp;quot;javascript&amp;quot;&amp;gt;/**
 * Types et Variables en Google Apps Script
 */
function exempleTypesVariablesGAS() {
    // Votre code ici
    var nombre = 42;
    var texte = &amp;quot;Bonjour, Google Apps Script!&amp;quot;;
    Logger.log(nombre);
    Logger.log(texte);
}&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_google_apps_script_の演算と演算子&amp;quot;&amp;gt;Google Apps Script の演算と演算子&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;Google Apps Scriptにおける演算と演算子はJavaScriptと同じです。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-javascript hljs&amp;quot; data-lang=&amp;quot;javascript&amp;quot;&amp;gt;/**
 * Opérations et Opérateurs en Google Apps Script
 */
function exempleOperationsGAS() {
    // Votre code ici
    var x = 10;
    var y = 5;
    var resultat = x + y;
    Logger.log(resultat);
}&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_google_apps_scriptにおけるvarletconst&amp;quot;&amp;gt;Google Apps Scriptにおけるvar、let、const&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;GAS では、概念の`var`, &amp;lt;code&amp;gt;let&amp;lt;/code&amp;gt;, et `const`は変数を宣言するために使用されます。ただし、それらの違いと影響を理解することが不可欠です。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-javascript hljs&amp;quot; data-lang=&amp;quot;javascript&amp;quot;&amp;gt;/**
 * Var, Let et Const en Google Apps Script
 */
function exempleVarLetConstGAS() {
    // Votre code ici
    // Utilisation de var
    var x = 10;
    if (true) {
        var x = 20; // La variable x est modifiée globalement
    }
    Logger.log(x);

    // Utilisation de let
    let y = 30;
    if (true) {
        let y = 40; // La variable y est limitée au bloc if
    }
    Logger.log(y);

    // Utilisation de const
    const z = 50;
    // z = 60; // Impossible de réassigner une constante
    Logger.log(z);
}&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_google_apps_script_の制御構造&amp;quot;&amp;gt;Google Apps Script の制御構造&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;制御構造など`if`, &amp;lt;code&amp;gt;else&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;while&amp;lt;/code&amp;gt; et `for`は、Google Apps Script で実行フローを管理するために使用されます。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-javascript hljs&amp;quot; data-lang=&amp;quot;javascript&amp;quot;&amp;gt;/**
 * Structures de Contrôle en Google Apps Script
 */
function exempleStructuresControleGAS() {
    // Votre code ici
    var condition = true;

    if (condition) {
        Logger.log(&amp;quot;La condition est vraie.&amp;quot;);
    } else {
        Logger.log(&amp;quot;La condition est fausse.&amp;quot;);
    }

    var compteur = 0;
    while (compteur &amp;amp;lt; 5) {
        Logger.log(compteur);
        compteur++;
    }

    for (var i = 0; i &amp;amp;lt; 3; i++) {
        Logger.log(i);
    }
}&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_google_apps_script_の設定とスコープ&amp;quot;&amp;gt;Google Apps Script の設定とスコープ&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;パラメータとスコープはGASスクリプト開発において重要な役割を果たします。その仕組みを理解して、予期しない動作を避けてください。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-javascript hljs&amp;quot; data-lang=&amp;quot;javascript&amp;quot;&amp;gt;/**
 * Paramètres et Scopes en Google Apps Script
 */
function exempleParametresScopesGAS(parametre) {
    // Votre code ici
    var variableGlobale = &amp;quot;Je suis global&amp;quot;;

    function afficherParametre() {
        Logger.log(parametre);
    }

    afficherParametre();
    Logger.log(variableGlobale);
}&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_google_apps_script_の定数変数および文字&amp;quot;&amp;gt;Google Apps Script の定数、変数、および文字&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;違いを理解する`const`, &amp;lt;code&amp;gt;var&amp;lt;/code&amp;gt;, et `let`これはGoogle Apps Scriptで変数を効果的に使用するために不可欠です。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-javascript hljs&amp;quot; data-lang=&amp;quot;javascript&amp;quot;&amp;gt;/**
 * Constantes, Variables, et Lettres en Google Apps Script
 */
function exempleConstantesVariablesLettresGAS() {
    // Votre code ici
    const constante = &amp;quot;Je ne change pas&amp;quot;;
    Logger.log(constante);

    var variable = &amp;quot;Je peux changer&amp;quot;;
    Logger.log(variable);

    let lettre = &amp;quot;Je peux aussi changer, mais seulement dans mon bloc&amp;quot;;
    Logger.log(lettre);
}&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_google_apps_script_でのループ&amp;quot;&amp;gt;Google Apps Script でのループ&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;ループ、例えば`for` et &amp;lt;code&amp;gt;while&amp;lt;/code&amp;gt;, 要素をイテレーションし、繰り返しの操作を行うために不可欠です。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-javascript hljs&amp;quot; data-lang=&amp;quot;javascript&amp;quot;&amp;gt;/**
 * Boucles en Google Apps Script
 */
function exempleBouclesGAS() {
    // Votre code ici
    for (var i = 0; i &amp;amp;lt; 3; i++) {
        Logger.log(i);
    }

    var condition = true;
    var compteur = 0;

    while (condition) {
        Logger.log(&amp;quot;Tour de boucle&amp;quot;);
        compteur++;
        if (compteur === 3) {
            condition = false;
        }
    }
}&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_google_apps_script_のオブジェクト&amp;quot;&amp;gt;Google Apps Script のオブジェクト&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;オブジェクトはデータを構造化するために使用されます。 GASでは、多数の組み込みオブジェクトがGoogleサービスとのやり取りを容易にします。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-javascript hljs&amp;quot; data-lang=&amp;quot;javascript&amp;quot;&amp;gt;/**
 * Objets en Google Apps Script
 */
function exempleObjetsGAS() {
    // Votre code ici
    var feuille = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
    var cellule = feuille.getRange(&amp;quot;A1&amp;quot;);
    cellule.setValue(&amp;quot;Nouvelle valeur&amp;quot;);
}&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_google_apps_scriptにおける定数変数および文字&amp;quot;&amp;gt;Google Apps Scriptにおける定数、変数、および文字&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;理解する違いの間`const`, &amp;lt;code&amp;gt;var&amp;lt;/code&amp;gt;, et `let`Google Apps Script で変数を効果的に使用することは不可欠です。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-javascript hljs&amp;quot; data-lang=&amp;quot;javascript&amp;quot;&amp;gt;/**
 * Constantes, Variables, et Lettres en Google Apps Script
 */
function exempleConstantesVariablesLettresGAS() {
    // Votre code ici
    const constante = &amp;quot;Je ne change pas&amp;quot;;
    Logger.log(constante);

    var variable = &amp;quot;Je peux changer&amp;quot;;
    Logger.log(variable);

    let lettre = &amp;quot;Je peux aussi changer, mais seulement dans mon bloc&amp;quot;;
    Logger.log(lettre);
}&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_google_apps_scriptの関数&amp;quot;&amp;gt;Google Apps Scriptの関数&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;関数はプログラミングにおける基本的な要素です。GASでは、関数をさまざまな方法で宣言および呼び出すことができます。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-javascript hljs&amp;quot; data-lang=&amp;quot;javascript&amp;quot;&amp;gt;/**
 * Fonctions en Google Apps Script
 */
function exempleFonctionsGAS() {
    // Votre code ici
    function additionner(a, b) {
        return a + b;
    }

    var resultat = additionner(2, 3);
    Logger.log(resultat);

    // Fonction anonyme
    var multiplier = function (x, y) {
        return x * y;
    };

    Logger.log(multiplier(4, 5));
}&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_google_apps_scriptのレスト演算子とスプレッド演算子&amp;quot;&amp;gt;Google Apps Scriptのレスト演算子とスプレッド演算子&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;オペレーターの休憩(&amp;lt;code&amp;gt;&amp;amp;#8230;&amp;amp;#8203;&amp;lt;/code&amp;gt;) と 伝播 の (&amp;lt;code&amp;gt;&amp;amp;#8230;&amp;amp;#8203;&amp;lt;/code&amp;gt;)は、配列とオブジェクトを簡潔に操作するのに便利です。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-javascript hljs&amp;quot; data-lang=&amp;quot;javascript&amp;quot;&amp;gt;/**
 * Opérateurs de Repos et de Propagation en Google Apps Script
 */
function exempleOperateursReposPropagationGAS() {
    // Votre code ici
    // Opérateur de repos (...) pour les tableaux
    var nombres = [1, 2, 3, 4, 5];
    var [...copieNombres] = nombres;
    Logger.log(copieNombres);

    // Opérateur de propagation (...) pour les objets
    var objOriginal = { x: 1, y: 2 };
    var objClone = { ...objOriginal, z: 3 };
    Logger.log(objClone);
}&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_google_apps_script_による分解による割り当て&amp;quot;&amp;gt;Google Apps Script による分解による割り当て&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;分解代入は、オブジェクトや配列から値を簡潔に抽出できる強力な機能です。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-javascript hljs&amp;quot; data-lang=&amp;quot;javascript&amp;quot;&amp;gt;/**
 * Affectation par Décomposition en Google Apps Script
 */
function exempleAffectationDecompositionGAS() {
    // Votre code ici
    var coordonnees = [3, 4];
    var [x, y] = coordonnees;
    Logger.log(x);
    Logger.log(y);

    var utilisateur = { nom: &amp;quot;John&amp;quot;, age: 30 };
    var { nom, age } = utilisateur;
    Logger.log(nom);
    Logger.log(age);
}&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_google_apps_scriptでのコレクションと宣言型プログラミング&amp;quot;&amp;gt;Google Apps Scriptでのコレクションと宣言型プログラミング&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;Google Apps Script は、配列などのデータ構造をサポートし、関数型プログラミングおよび宣言的イテレーション（&amp;amp;gt;&amp;amp;lt;impérative）、ような`map`, &amp;lt;code&amp;gt;reduce&amp;lt;/code&amp;gt; et &amp;lt;code&amp;gt;forEach&amp;lt;/code&amp;gt;。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-javascript hljs&amp;quot; data-lang=&amp;quot;javascript&amp;quot;&amp;gt;/**
 * Collections et Programmation Déclarative en Google Apps Script
 */
function exempleCollectionsFonctionnelleGAS() {
    // Votre code ici
    // Exemple de tableau (collection)
    var nombres = [1, 2, 3, 4, 5];

    // Utilisation de forEach
    nombres.forEach(function (nombre) {
        Logger.log(nombre);
    });

    // Utilisation de map
    var carresNombres = nombres.map(function (nombre) {
        return nombre * nombre;
    });
    Logger.log(carresNombres);

    // Utilisation de reduce
    var somme = nombres.reduce(function (acc, nombre) {
        return acc + nombre;
    }, 0);
    Logger.log(somme);
}&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_結論&amp;quot;&amp;gt;結論&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;このメモは、具体的なコード例を使ってGoogle Apps Scriptの基本概念を説明しました。これらの知識を使って、日常のタスクを自動化し、ドキュメントをカスタマイズし、Google Apps Scriptの機能をフルに活用してください。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;</description>
        </item><item>
            <title>Googleフォーム スクリプトと自動化のエクスプレス研修</title>
            <link >https://cheroliv.com/blog/2023/0067_formation_express_sur_google_forms_script_post.html</link>
            <pubDate>Wed, 20 Dec 2023 00:00:00 +0000</pubDate>
            <guid isPermaLink="false">blog/2023/0067_formation_express_sur_google_forms_script_post.html</guid>
            <description>&amp;lt;div id=&amp;quot;preamble&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;所要時間：30分&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_目標&amp;quot;&amp;gt;目標&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;Forms での Google Apps Script の基礎を理解する - スクリプトエディタにアクセスして、トリガーで命令を実行する方法を学ぶ&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_遅延&amp;quot;&amp;gt;遅延&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;olist arabic&amp;quot;&amp;gt;
&amp;lt;ol class=&amp;quot;arabic&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;Google Form スクリプト入門&amp;lt;/strong&amp;gt;(5分)&amp;lt;/p&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;Google Form Script のクイック概要 - 主要機能の紹介&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;Googleフォームおよび関連スクリプトの作成&amp;lt;/strong&amp;gt;(5 分)&amp;lt;/p&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;シンプルなフォームを Google Forms で作成 - 関連スクリプトエディターの紹介&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;命令を実行する&amp;lt;/strong&amp;gt;(10 分)&amp;lt;/p&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;「on start」トリガーの設定 - トリガーの設定 &amp;quot;on submit - 指令を実行するスクリプトを書く - 素早いテストでジャーナル内の正常な動作を確認する&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;結果の分析とベストプラクティス&amp;lt;/strong&amp;gt;(10分)&amp;lt;/p&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;指示の実行結果の検証 - スクリプトの例に関する議論と、自動化によって時間を短縮できる方法&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ol&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_前提条件&amp;quot;&amp;gt;前提条件&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;Googleアカウントを持ち、Google FormsおよびGoogle Sheetsへのアクセスがある&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_機材&amp;quot;&amp;gt;機材&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;ウェブブラウザとインターネット接続があるコンピュータ&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_注記&amp;quot;&amp;gt;注記&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;このショートトレーニングは、Google Form Scriptを使った自動化へのクイックイントロダクションを提供します。 より深い理解のために、より長い研修が推奨されます。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_1_google_form_スクリプトの紹介&amp;quot;&amp;gt;1 - Google Form スクリプトの紹介&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_スライド_1_google_form_scriptのクイック概要&amp;quot;&amp;gt;スライド 1: Google Form Scriptのクイック概要&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;Google Form ScriptはGoogle Forms に統合されたスクリプトプラットフォームです。 - カスタマイズ可能な機能を追加し、タスクを自動化できます。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_slide_2_主要機能のプレゼンテーション&amp;quot;&amp;gt;Slide 2: 主要機能のプレゼンテーション&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;スクリプトエディタ : Google Apps Script を書くための組み込みスクリプトエディタ。 - トリガー:「on submit」などのイベントがスクリプトの実行を起動する。&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_slide_3_google_form_スクリプトを使用する利点&amp;quot;&amp;gt;Slide 3: Google Form スクリプトを使用する利点&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;カスタマイズ : 独自の機能を備えたカスタムフォームを作成します。 自動化：フォームの回答に応じてアクションを自動化してください。 - 統合 : スクリプトを他のGoogleサービスと統合して、より充実した体験を提供します。&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_発表者への注記&amp;quot;&amp;gt;発表者への注記：&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;これらの機能は、フォームをカスタマイズおよび自動化するための大きな可能性を提供します。 この研修の続きでは、スクリプトと特定の自動化の作成について詳しく探ります。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;https://developers.google.com/apps-script/add-ons/editors/forms?hl=fr&amp;quot; class=&amp;quot;bare&amp;quot;&amp;gt;https://developers.google.com/apps-script/add-ons/editors/forms?hl=fr&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;https://developers.google.com/apps-script/reference/forms?hl=fr&amp;quot; class=&amp;quot;bare&amp;quot;&amp;gt;https://developers.google.com/apps-script/reference/forms?hl=fr&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;https://developers.google.com/apps-script/reference/forms/form-app?hl=fr&amp;quot; class=&amp;quot;bare&amp;quot;&amp;gt;https://developers.google.com/apps-script/reference/forms/form-app?hl=fr&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_googleフォームと関連スクリプトの作成_5分&amp;quot;&amp;gt;Googleフォームと関連スクリプトの作成 (5分)&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;

&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;</description>
        </item><item>
            <title>パイソンメモ</title>
            <link >https://cheroliv.com/blog/2023/0066_memo_python_post.html</link>
            <pubDate>Sun, 19 Nov 2023 00:00:00 +0000</pubDate>
            <guid isPermaLink="false">blog/2023/0066_memo_python_post.html</guid>
            <description>&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_windowsにpythonをインストール&amp;quot;&amp;gt;WindowsにPythonをインストール&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;https://ninite.com/pythonx3/&amp;quot;&amp;gt;Windows での Python&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;https://python-docs.readthedocs.io/en/latest/starting/install3/win.html&amp;quot; class=&amp;quot;bare&amp;quot;&amp;gt;https://python-docs.readthedocs.io/en/latest/starting/install3/win.html&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;https://python-docs.readthedocs.io/en/latest/dev/virtualenvs.html#virtualenvironments-ref&amp;quot; class=&amp;quot;bare&amp;quot;&amp;gt;https://python-docs.readthedocs.io/en/latest/dev/virtualenvs.html#virtualenvironments-ref&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_pythonを実行中&amp;quot;&amp;gt;Pythonを実行中&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;\.問題点：Python venv&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;参照 :&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;cd mon_projet

python -m venv mon_venv

source mon_venv/bin/activate

# Sur windows
mon_venv\Scripts\activate

deactivate&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_インストール要件&amp;quot;&amp;gt;インストール要件&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;pip install -r requirements.txt&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_開始&amp;quot;&amp;gt;開始&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;https://python.doctor/page-apprendre-programmation-orientee-objet-poo-classes-python-cours-debutants&amp;quot;&amp;gt;Python の オブジェクト指向&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_pythonでのgofのデザインパターン&amp;quot;&amp;gt;PythonでのGoFのデザインパターン&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;https://github.com/whikwon/python-patterns/&amp;quot;&amp;gt;実装 1&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;https://github.com/Sean-Bradley/Design-Patterns-In-Python&amp;quot;&amp;gt;実装 2&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;https://sbcode.net/python/&amp;quot;&amp;gt;完全な本&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;GoFのデザインパターンは、『Design Patterns: Elements of Reusable Object-Oriented Software』という書籍で説明された23のデザインパターンのセットです。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;以下はGoFのデザインパターンの一覧です&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;table class=&amp;quot;tableblock frame-all grid-all stretch&amp;quot;&amp;gt;
&amp;lt;colgroup&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.0833%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.0833%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.0833%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.0833%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.0833%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.0833%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.0833%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.0833%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.0833%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.0833%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.0833%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.0833%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.0833%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.0833%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.0833%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.0833%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.0833%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.0833%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.0833%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.0833%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.0833%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.0833%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.0833%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.0833%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.0833%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.0833%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.0833%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.0833%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.0833%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.0833%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.0833%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.0833%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.0833%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.0833%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.0833%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.0833%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.0833%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.0833%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.0833%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.0833%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.0833%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.0833%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.0833%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.0833%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.0833%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.0833%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.0833%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 2.0849%;&amp;quot;&amp;gt;
&amp;lt;/colgroup&amp;gt;
&amp;lt;tbody&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;名前&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;説明&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;ファクトリーメソッド&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;具体的にインスタンス化するクラスを指定せずにオブジェクトを作成する。&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;�抽象ファクトリー&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;具体的なクラスを指定せずに、関連または依存するオブジェクトのファミリーを作成する。&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;ビルダー&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;複雑なオブジェクトの構築をその表現から分離し、同じ構築プロセスで異なる表現を作成できるようにします。&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;プロトタイプ&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;既存のプロトタイプをコピーして新しいオブジェクトを作成する&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;シングルトン&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;クラスのインスタンス化を1つのオブジェクトに制限します。&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;アダプター&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;クラスのインターフェイスをクライアントが期待する別のインターフェイスに変換します。&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;橋&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;抽象をその実装から切り離し、両者が独立して変化できるようにする。&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;複合&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;オブジェクトをツリー構造に組み合わせて、部分-全体の階層を表現します。&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;デコレーター&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;動的にオブジェクトに追加の責任を付ける。&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;ファサード&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;サブシステム内のインターフェースのセットに対して、統一されたインターフェースを提供します。&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;フライウェイト&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;軽量オブジェクトの作成と使用のコストを削減します。&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;プロキシ&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;別のオブジェクトへのアクセスを制御するために、そのオブジェクトの代替またはプレースホルダーを提供します。&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;責任の連鎖&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;複数のオブジェクトが要求を処理できるようにします。&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;コマンド&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;リクエストをオブジェクトにカプセル化し、これにより、異なるリクエスト、キュー、またはログを持つクライアントをパラメータ化し、元に戻せる操作をサポートします。&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;通訳&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;言語の文法の表現を与え、その表現を使用してその言語の文を解釈する。&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;イテレータ&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;集約オブジェクトの要素を、内部表現を公開することなく順に巡回する手段を提供する。&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;調停者&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;オブジェクト間の複雑な依存関係を減らし、オブジェクトが仲介者オブジェクトを通じてのみ通信できるようにする。&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;メメント&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;オブジェクトをその前の状態に戻す機能を提供します（カプセル化を侵害せずに）。&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;観察する&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;1対多の依存関係をオブジェクト間に定義し、オブジェクトの状態が変化すると、そのすべての依存先が通知され、自動的に更新されます。&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;状態&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;オブジェクトが内部状態が変わったときに振る舞いを変更できるようにする。&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;戦略&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;アルゴリズムの一族を定義し、それぞれをカプセル化して交換可能にする。&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;テンプレートメソッド&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;アルゴリズムのスケルトンをメソッド内で定義し、いくつかの手順をサブクラスに委譲する。&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;�訪問者&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;オブジェクト構造に対して新しい操作を定義し、オブジェクトのクラスを変更せずに実行することができます。&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/tbody&amp;gt;
&amp;lt;/table&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_関数型プログラミング&amp;quot;&amp;gt;関数型プログラミング&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;table class=&amp;quot;tableblock frame-all grid-all stretch&amp;quot;&amp;gt;
&amp;lt;colgroup&amp;gt;
&amp;lt;col style=&amp;quot;width: 16.6666%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 27.7777%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 55.5557%;&amp;quot;&amp;gt;
&amp;lt;/colgroup&amp;gt;
&amp;lt;tbody&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;図書館&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;URL&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;説明&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;PyMonad&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;https://github.com/jasondelaat/pymonad&amp;quot; class=&amp;quot;bare&amp;quot;&amp;gt;https://github.com/jasondelaat/pymonad&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;PyMonadは、HaskellやF#などのプログラミング言語に基づいたPythonでのモナディックデータ構造の実装であり、関数型プログラミングで最も一般的に使用されるモナド型の実装を含みます。https://www.miguelfarrajota.com/2021/06/monads-in-python-with-pymonad/[記事]&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;PyFunctional&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;https://github.com/EntilZha/PyFunctional/&amp;quot; class=&amp;quot;bare&amp;quot;&amp;gt;https://github.com/EntilZha/PyFunctional/&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;PyFunctionalは、純粋な関数とイテラブルを扱うためのツールを提供するPython用の関数型プログラミングライブラリです。&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;ツールズ&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;https://toolz.readthedocs.io/en/latest/&amp;quot; class=&amp;quot;bare&amp;quot;&amp;gt;https://toolz.readthedocs.io/en/latest/&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;Toolz は、純粋な関数とイテラブルを扱うためのツールを提供する関数型プログラミング向けの Python ライブラリです。&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;Fn.py&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;https://github.com/kachayev/fn.py&amp;quot; class=&amp;quot;bare&amp;quot;&amp;gt;https://github.com/kachayev/fn.py&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;Fn.pyは、純粋関数とイテラブルを扱うためのツールを提供する関数型プログラミング向けのPythonライブラリです。&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;ココナッツ&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;https://coconut-lang.org/&amp;quot; class=&amp;quot;bare&amp;quot;&amp;gt;https://coconut-lang.org/&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;Coconut は Python に関数型プログラミングのためのいくつかの機能を追加し、パターンマッチングも含まれます。https://stackoverflow.com/questions/11909681/are-there-pattern-matching-functions-in-python-like-this[会話ソフ]&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/tbody&amp;gt;
&amp;lt;/table&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_副作用&amp;quot;&amp;gt;副作用&amp;lt;/h3&amp;gt;

&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_ループ&amp;quot;&amp;gt;ループ&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-python hljs&amp;quot; data-lang=&amp;quot;python&amp;quot;&amp;gt;# impérative way
result = []
for i in inputs:
    x = f(g(i))
    result.append(x)

# idiomatic way
result = map(comp(f,g), inputs)&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;</description>
        </item><item>
            <title>ウェブ開発者</title>
            <link >https://cheroliv.com/blog/2023/0065_training_web_dev_post.html</link>
            <pubDate>Thu, 24 Aug 2023 00:00:00 +0000</pubDate>
            <guid isPermaLink="false">blog/2023/0065_training_web_dev_post.html</guid>
            <description></description>
        </item><item>
            <title>トレーディングカードゲーム (TCG)</title>
            <link >https://cheroliv.com/blog/2023/0064_training_trading_card_games_post.html</link>
            <pubDate>Mon, 21 Aug 2023 00:00:00 +0000</pubDate>
            <guid isPermaLink="false">blog/2023/0064_training_trading_card_games_post.html</guid>
            <description></description>
        </item><item>
            <title>TypeScriptメモ</title>
            <link >https://cheroliv.com/blog/2023/0063_memo_ts_post.html</link>
            <pubDate>Sat, 19 Aug 2023 00:00:00 +0000</pubDate>
            <guid isPermaLink="false">blog/2023/0063_memo_ts_post.html</guid>
            <description>&amp;lt;div id=&amp;quot;preamble&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;GitHub リポジトリ:https://github.com/cheroliv/ts-codebase[ts-codebase, window=&amp;quot;_blank]&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;toc_ts&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;underline&amp;quot;&amp;gt;Intro typescript&amp;lt;/span&amp;gt;&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;olist arabic&amp;quot;&amp;gt;
&amp;lt;ol class=&amp;quot;arabic&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;#ts_types&amp;quot;&amp;gt;TypeScriptの型&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;#機能&amp;quot;&amp;gt;[機能]&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;#data_struct&amp;quot;&amp;gt;データ構造&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;#enums_tuples&amp;quot;&amp;gt;列挙型とタプル&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;#void_never&amp;quot;&amp;gt;Void と Never&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;#class_interface&amp;quot;&amp;gt;クラスとインターフェース&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;#tsconfig&amp;quot;&amp;gt;tsconfig.json ファイル&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;#モジュール&amp;quot;&amp;gt;[モジュール]&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;#約束&amp;quot;&amp;gt;約束&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;async-await&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;#ジェネリクス&amp;quot;&amp;gt;[ジェネリクス]&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ol&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;index.html&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-html hljs&amp;quot; data-lang=&amp;quot;html&amp;quot;&amp;gt;&amp;amp;lt;!DOCTYPE html&amp;amp;gt;
&amp;amp;lt;html lang=&amp;quot;fr&amp;quot;&amp;amp;gt;

&amp;amp;lt;head&amp;amp;gt;
    &amp;amp;lt;meta charset=&amp;quot;UTF-8&amp;quot;&amp;amp;gt;
    &amp;amp;lt;meta name=&amp;quot;viewport&amp;quot; content=&amp;quot;width=device-width, initial-scale=1.0&amp;quot; /&amp;amp;gt;
    &amp;amp;lt;meta http-equiv=&amp;quot;X-UA-Compatible&amp;quot; content=&amp;quot;ie=edge&amp;quot; /&amp;amp;gt;
    &amp;amp;lt;title&amp;amp;gt;Document&amp;amp;lt;/title&amp;amp;gt;
&amp;amp;lt;/head&amp;amp;gt;

&amp;amp;lt;body&amp;amp;gt;
    Intro typescript
    &amp;amp;lt;script src=&amp;quot;01_types.js&amp;quot;&amp;amp;gt;&amp;amp;lt;/script&amp;amp;gt;
    &amp;amp;lt;script src=&amp;quot;02_data_structure.js&amp;quot;&amp;amp;gt;&amp;amp;lt;/script&amp;amp;gt;
    &amp;amp;lt;script src=&amp;quot;03_enums_tuples.js&amp;quot;&amp;amp;gt;&amp;amp;lt;/script&amp;amp;gt;
&amp;amp;lt;/body&amp;amp;gt;

&amp;amp;lt;/html&amp;amp;gt;&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;ts_types&amp;quot;&amp;gt;TypeScriptの型&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;01_types.ts&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-typescript hljs&amp;quot; data-lang=&amp;quot;typescript&amp;quot;&amp;gt;/**
 * Les types en typescript
 */

//quand le type n&amp;#39;est pas defini des le debut,
// alors il est réassignable
// c&amp;#39;est le type Any qui est attribué par défaut
let my_var;
my_var = &amp;quot;username&amp;quot;;
console.assert(my_var === &amp;quot;username&amp;quot;);
my_var = 11;
console.assert(my_var === 11);
my_var = true;
console.assert(my_var === true);

let age = 1;
console.assert(age === 1);
age = 2;
// age=&amp;quot;trois&amp;quot; c&amp;#39;est impossible
// car l&amp;#39;inference de type a attribué le type number
console.assert(age === 2);

// Déclaration explicite de type
let pi: Number = 3.14;
console.assert(typeof pi === &amp;quot;number&amp;quot;);&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;#toc_ts&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;underline&amp;quot;&amp;gt;Intro typescript&amp;lt;/span&amp;gt;&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;関数&amp;quot;&amp;gt;関数&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;関数は再利用可能なコードブロックです。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;例の得点 :&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-typescript hljs&amp;quot; data-lang=&amp;quot;typescript&amp;quot;&amp;gt;const add = (a: number, b: number): number =&amp;amp;gt; a + b;&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;#toc_ts&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;underline&amp;quot;&amp;gt;Intro typescript&amp;lt;/span&amp;gt;&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;data_struct&amp;quot;&amp;gt;データ構造&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;02_data_structure.ts&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-typescript hljs&amp;quot; data-lang=&amp;quot;typescript&amp;quot;&amp;gt;/***
 * Structure de données:
 * Avec le type any on peut changer
 * le type de la variable à tout instruction
 * Lorsque l&amp;#39;on fixe le type
 * alors il n&amp;#39;est plus possible de le changer
 * lors d&amp;#39;une assignation
 */

// Arrays
let buddies: any[] = [
    &amp;quot;cheroliv&amp;quot;,
    &amp;quot;imrandeh&amp;quot;,
    &amp;quot;issoudeh&amp;quot;,
    &amp;quot;soumi92&amp;quot;
]

console.assert(buddies[0] === &amp;quot;cheroliv&amp;quot;);
console.assert(buddies[1] === &amp;quot;imrandeh&amp;quot;);
console.assert(buddies[2] === &amp;quot;issoudeh&amp;quot;);
console.assert(buddies[3] === &amp;quot;soumi92&amp;quot;);
// Déclaré en type any, l&amp;#39;inference de type
// a bien réaligné en type string
console.assert(typeof buddies[0] === &amp;quot;string&amp;quot;);
console.assert(typeof buddies[1] === &amp;quot;string&amp;quot;);
console.assert(typeof buddies[2] === &amp;quot;string&amp;quot;);
console.assert(typeof buddies[3] === &amp;quot;string&amp;quot;);



let writers: (String | String | String | Number)[][] = [
    [&amp;quot;Chrétien&amp;quot;, &amp;quot;de Troyes&amp;quot;, &amp;quot;fr&amp;quot;, 12],
    [&amp;quot;François&amp;quot;, &amp;quot;Rabelais&amp;quot;, &amp;quot;fr&amp;quot;, 16],
    [&amp;quot;René&amp;quot;, &amp;quot;Descartes&amp;quot;, &amp;quot;fr&amp;quot;, 17],
    [&amp;quot;Jean-Jacques&amp;quot;, &amp;quot;Rousseau&amp;quot;, &amp;quot;fr&amp;quot;, 18],
    [&amp;quot;Georg&amp;quot;, &amp;quot;Hegel&amp;quot;, &amp;quot;de&amp;quot;, 19],
    [&amp;quot;Karl&amp;quot;, &amp;quot;Marx&amp;quot;, &amp;quot;de&amp;quot;, 19],
    [&amp;quot;Friedrich&amp;quot;, &amp;quot;Engels&amp;quot;, &amp;quot;de&amp;quot;, 19],
    [&amp;quot;Victor&amp;quot;, &amp;quot;Hugo&amp;quot;, &amp;quot;fr&amp;quot;, 19],
    [&amp;quot;Paul&amp;quot;, &amp;quot;Verlaine&amp;quot;, &amp;quot;fr&amp;quot;, 19],
    [&amp;quot;Arthur&amp;quot;, &amp;quot;Rimbaud&amp;quot;, &amp;quot;fr&amp;quot;, 19],
    [&amp;quot;Gérard&amp;quot;, &amp;quot;de Nerval&amp;quot;, &amp;quot;fr&amp;quot;, 19],
    [&amp;quot;Georg&amp;quot;, &amp;quot;Lukacs&amp;quot;, &amp;quot;hu&amp;quot;, 20],
    [&amp;quot;Franz&amp;quot;, &amp;quot;Kafka&amp;quot;, &amp;quot;hu&amp;quot;, 20],
    [&amp;quot;Antonio&amp;quot;, &amp;quot;Gramsci&amp;quot;, &amp;quot;it&amp;quot;, 20],
    [&amp;quot;Domenico&amp;quot;,&amp;quot;Losurdo&amp;quot;,&amp;quot;it&amp;quot;,20],
];

// console.table(writers);


// Objects
let author: {
    first_name: String,
    last_name: String,
    lang: String,
    century: Number
} = {
    // slice(-1) renvoie le dernier élèment
    first_name: writers.slice(-1)[0][0] as String,
    last_name: writers.slice(-1)[0][1] as String,
    lang: writers.slice(-1)[0][2] as String,
    century: writers.slice(-1)[0][3] as Number,
}


// assertion sur la valeur en accés par encapsulation(dot)
console.assert(author.first_name === &amp;quot;Antonio&amp;quot;)
console.assert(author.last_name === &amp;quot;Gramsci&amp;quot;)
console.assert(author.lang === &amp;quot;it&amp;quot;)
console.assert(author.century === 20);

// assertion sur le type en accès par index
console.assert(typeof author[&amp;quot;first_name&amp;quot;] === &amp;quot;string&amp;quot;)
console.assert(typeof author[&amp;quot;last_name&amp;quot;] === &amp;quot;string&amp;quot;)
console.assert(typeof author[&amp;quot;lang&amp;quot;] === &amp;quot;string&amp;quot;)
console.assert(typeof author[&amp;quot;century&amp;quot;] === &amp;quot;number&amp;quot;);&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;#toc_ts&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;underline&amp;quot;&amp;gt;Intro typescript&amp;lt;/span&amp;gt;&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;enums_tuples&amp;quot;&amp;gt;列挙型とタプル&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;03_列挙型_タプル.ts&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-typescript hljs&amp;quot; data-lang=&amp;quot;typescript&amp;quot;&amp;gt;/**
 * Enums et Tuples
 *
 * Enum: il existe les enums numérique
 * et les enums chaine de caracteres.
 *
 * Tuple: similaire aux arrays mais ne peut
 * contenir qu&amp;#39;une valeur de type spécifié.
 *
 */

//Enum numérique
// l&amp;#39;index par de debut défaut est 0
// ici on le place a 1
enum Week {
    Monday = 1,
    Tuesday = 2,
    Wednesday = 3,
    Thursday = 4,
    Friday = 5,
    Saturday = 6,
    Sunday = 7,
};

console.assert(Week.Monday == 1);
console.assert(Week.Tuesday == 2);
console.assert(Week.Wednesday == 3);
console.assert(Week.Thursday == 4);
console.assert(Week.Friday == 5);
console.assert(Week.Saturday == 6);
console.assert(Week.Sunday == 7);

console.assert(Week[1] === &amp;quot;Monday&amp;quot;);
console.assert(Week[2] === &amp;quot;Tuesday&amp;quot;);
console.assert(Week[3] === &amp;quot;Wednesday&amp;quot;);
console.assert(Week[4] === &amp;quot;Thursday&amp;quot;);
console.assert(Week[5] === &amp;quot;Friday&amp;quot;);
console.assert(Week[6] === &amp;quot;Saturday&amp;quot;);
console.assert(Week[7] === &amp;quot;Sunday&amp;quot;);

let motd_arr_fr: String[] = [
    &amp;quot;Associé à la Lune&amp;quot;,
    &amp;quot;Du dieu Tiw, associé à Mars&amp;quot;,
    &amp;quot;Du dieu germanique Odin&amp;quot;,
    &amp;quot;Du dieu germanique du tonnerre Thor&amp;quot;,
    &amp;quot;De la déesse germanique Frigga associée à Vénus&amp;quot;,
    &amp;quot;Associé à Saturne&amp;quot;,
    &amp;quot;Associé au Soleil&amp;quot;,
];

let motd_arr_en: String[] = [
    &amp;quot;associated with the Moon&amp;quot;,
    &amp;quot;from the god Tiw, associated with Mars&amp;quot;,
    &amp;quot;from Germanic god Odin&amp;quot;,
    &amp;quot;from Germanic god of thunder Thor&amp;quot;,
    &amp;quot;from Germanic goddess Frigga associated with Venus&amp;quot;,
    &amp;quot;associated with Saturn&amp;quot;,
    &amp;quot;associated with the Sun&amp;quot;,
];

// Un tuple (triple)
let monday_triple_fr: [
    Number,
    String,
    String
] = [
        Week.Monday,
        Week[Week.Monday],
        motd_arr_fr[0],
    ];


console.assert(monday_triple_fr[0] === 1);
console.assert(monday_triple_fr[1] === &amp;quot;Monday&amp;quot;);
console.assert(monday_triple_fr[2] === &amp;quot;Associé à la Lune&amp;quot;);


let monday_triple_en: [
    Number,
    String,
    String
] = [
        Week.Monday,
        Week[Week.Monday],
        motd_arr_en[0],
    ];

console.assert(monday_triple_en[0] === 1);
console.assert(monday_triple_en[1] === &amp;quot;Monday&amp;quot;);
console.assert(monday_triple_en[2] === &amp;quot;associated with the Moon&amp;quot;);


// On se fait un type pour ajouter le nom de la langue
type Meaning_of_the_day = {
    lang: String,
    meaning: (Week | String)[][],
};

//fonction d&amp;#39;affichage du type Meaning_of_the_day
const display_motd = (motd: Meaning_of_the_day) =&amp;amp;gt; {
    motd.meaning.forEach(day =&amp;amp;gt;
        console.table(`${Week[day[0] as Week]}: ${day[1]}.(${motd.lang})`)
    )
};

//fonction d&amp;#39;assertion sur le type Meaning_of_the_day
// afin de verifier la concordance du contenu avec
// motd_arr_#lang#
const test_motd = (
    motd: Meaning_of_the_day,
    motd_arr: String[]
) =&amp;amp;gt; {
    console.assert(motd.lang.length === 2)
    for (const [i, value] of motd.meaning.entries()) {
        console.assert(value[1] === motd_arr[i]);
    }
};


let motd_fr: Meaning_of_the_day = {
    lang: &amp;quot;fr&amp;quot;,
    meaning: [
        [Week.Monday, motd_arr_fr[0]],
        [Week.Tuesday, motd_arr_fr[1]],
        [Week.Wednesday, motd_arr_fr[2]],
        [Week.Thursday, motd_arr_fr[3]],
        [Week.Friday, motd_arr_fr[4]],
        [Week.Saturday, motd_arr_fr[5]],
        [Week.Sunday, motd_arr_fr[6]],
    ],
}

console.log(&amp;quot;---------&amp;quot;);
console.log(&amp;quot;display_motd(motd_fr):&amp;quot;);
display_motd(motd_fr);
test_motd(motd_fr, motd_arr_fr)


let motd_en: Meaning_of_the_day = {
    lang: &amp;quot;en&amp;quot;,
    meaning: [
        [Week.Monday, motd_arr_en[0]],
        [Week.Tuesday, motd_arr_en[1]],
        [Week.Wednesday, motd_arr_en[2]],
        [Week.Thursday, motd_arr_en[3]],
        [Week.Friday, motd_arr_en[4]],
        [Week.Saturday, motd_arr_en[5]],
        [Week.Sunday, motd_arr_en[6]],
    ],
}

console.log(&amp;quot;---------&amp;quot;);
console.log(&amp;quot;display_motd(motd_en):&amp;quot;);
display_motd(motd_en);
console.log(&amp;quot;---------&amp;quot;);
test_motd(motd_en, motd_arr_en);

// Un tuple (triple) utilisant le type
// Meaning_of_the_day pour peupler le meaning
let motd_triple: [
    Number,
    String,
    String
] = [
        Week.Monday,
        Week[Week.Monday],
        motd_fr.meaning[0][1] as String
    ];

console.assert(motd_triple[0] === 1);
console.assert(motd_triple[1] === &amp;quot;Monday&amp;quot;);
console.assert(motd_triple[2] === &amp;quot;Associé à la Lune&amp;quot;);&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;#toc_ts&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;underline&amp;quot;&amp;gt;Intro typescript&amp;lt;/span&amp;gt;&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;void_never&amp;quot;&amp;gt;Void と Never&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;04_void_never_types.ts&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-typescript hljs&amp;quot; data-lang=&amp;quot;typescript&amp;quot;&amp;gt;// Le type void est l&amp;#39;opposé du type any
// c&amp;#39;est l&amp;#39;absence de type.
function verify_writers_length(): void {
    console.assert(writers.length &amp;amp;gt; 0);
}

verify_writers_length();

const verify_writers_length_arrow = (): void =&amp;amp;gt;
    console.assert(writers.length &amp;amp;gt; 0);

verify_writers_length_arrow();

//Type of et never
let value = 30;
console.assert(typeof value === &amp;quot;number&amp;quot;);

//never: qqchs qui n&amp;#39;arrive jamais
function foo(x: String | Number): Boolean {
    if (typeof x === &amp;quot;string&amp;quot;) {
        return true;
    } else if (typeof x === &amp;quot;number&amp;quot;) {
        return false;
    }
    return fail(&amp;quot;Error!&amp;quot;)
}

function fail(message: String): never {
    throw new Error(message as string);
}&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;#toc_ts&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;underline&amp;quot;&amp;gt;Intro typescript&amp;lt;/span&amp;gt;&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;class_interface&amp;quot;&amp;gt;クラスとインターフェース&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;04_void_never_types.ts&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-typescript hljs&amp;quot; data-lang=&amp;quot;typescript&amp;quot;&amp;gt;/**
 * Les classes:
 * members,
 * visibility,
 * nommage,
 * accesseurs
 * scope identifier: static,private,protected
 *
 * convention de nommage :
 * Les membres private sont préfixés avec un _ *
 */

class Member {
    username: String = &amp;quot;&amp;quot;;
    email: String = &amp;quot;&amp;quot;;
    private _password: String = &amp;quot;&amp;quot;;
    readonly signup_date: Date = new Date(Date.now());

    constructor(username: String, email: String) {
        this.username = username;
        this.email = email;
    }

    get password(): String {
        return this._password;
    }

    set password(new_password: String) {
        this._password = new_password;
    }

    /**
     * Une fonction static qui initilise un member,
     * à partir d&amp;#39;un author
     */
    static fromAuthor(author: {
        first_name: String,
        last_name: String,
        lang: String,
        century: Number
    }): Member {
        return new Member(
            `${author.first_name}.${author.last_name}`,
            `${author.first_name}.${author.last_name}@acme.com`,
        );
    }
};


let domenico = Member.fromAuthor(author);
domenico.password = &amp;quot;test&amp;quot;;

console.assert(domenico.email === &amp;quot;Domenico.Losurdo@acme.com&amp;quot;);
console.assert(domenico.password === &amp;quot;test&amp;quot;);


// Héritage
enum Forms {
    Undefined = 0,
    Polygones = 1,
    Circle = 2,
    Straight = 3,
    Segment = 4,
};

class Form {
    type: Forms = Forms.Undefined;
};

class Rectangle extends Form {
    h: Number = 0;
    w: Number = 0;
};

class Square extends Rectangle {
    side: Number = 0;
};


/**
 * Interface donne un contrat à un type.
 * Les interfaces permettent de définir la structure d&amp;#39;un objet.
 */

interface IPerson {
    username: String;
    email: String;
    readonly signup_date: Date;
}

const user1: IPerson = {
    username: Member.fromAuthor(author)[&amp;quot;username&amp;quot;],
    email: Member.fromAuthor(author)[&amp;quot;email&amp;quot;],
    signup_date: Member.fromAuthor(author)[&amp;quot;signup_date&amp;quot;],
}&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;#toc_ts&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;underline&amp;quot;&amp;gt;Intro typescript&amp;lt;/span&amp;gt;&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;tsconfig&amp;quot;&amp;gt;tsconfig.json ファイル&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;tsconfig.json&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-json hljs&amp;quot; data-lang=&amp;quot;json&amp;quot;&amp;gt;{
  /* Visit https://aka.ms/tsconfig to read more about this file */
  &amp;quot;compileOnSave&amp;quot;: true,

  &amp;quot;compilerOptions&amp;quot;: {
    &amp;quot;target&amp;quot;: &amp;quot;es2016&amp;quot;,
    &amp;quot;module&amp;quot;: &amp;quot;CommonJS&amp;quot;,
    &amp;quot;noEmitOnError&amp;quot;: true,
    &amp;quot;strict&amp;quot;: true,
    &amp;quot;noImplicitAny&amp;quot;: true,
    &amp;quot;esModuleInterop&amp;quot;: true
  }
}&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;#toc_ts&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;underline&amp;quot;&amp;gt;Intro typescript&amp;lt;/span&amp;gt;&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_モジュール&amp;quot;&amp;gt;モジュール&amp;lt;a id=&amp;quot;モジュール&amp;quot;&amp;gt;&amp;lt;/a&amp;gt;&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;モジュールは、コードを複数のファイルに整理することを可能にします。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;例の評価：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-typescript hljs&amp;quot; data-lang=&amp;quot;typescript&amp;quot;&amp;gt;// Dans un fichier math.ts
export const add = (a: number, b: number): number =&amp;amp;gt; a + b;

// Dans un autre fichier
import { add } from &amp;#39;./math&amp;#39;;
let result = add(2, 3);&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;#toc_ts&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;underline&amp;quot;&amp;gt;Intro typescript&amp;lt;/span&amp;gt;&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;約束&amp;quot;&amp;gt;約束&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;プロミスは、非同期操作を実行するために使用されます。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;例：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-typescript hljs&amp;quot; data-lang=&amp;quot;typescript&amp;quot;&amp;gt;const promise = new Promise&amp;amp;lt;string&amp;amp;gt;((resolve) =&amp;amp;gt; {
    // Code asynchrone ici
    resolve(&amp;quot;Succès&amp;quot;);
});

promise.then((result) =&amp;amp;gt; {
    console.log(result);
});&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;#toc_ts&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;underline&amp;quot;&amp;gt;Intro typescript&amp;lt;/span&amp;gt;&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;async-await&amp;quot;&amp;gt;async/await&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;async/await はプロミスの処理を簡素化します。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;例：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-typescript hljs&amp;quot; data-lang=&amp;quot;typescript&amp;quot;&amp;gt;const fetchData = async (): Promise&amp;amp;lt;void&amp;amp;gt; =&amp;amp;gt; {
    const result = await someAsyncFunction();
    console.log(result);
};&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;#toc_ts&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;underline&amp;quot;&amp;gt;Intro typescript&amp;lt;/span&amp;gt;&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;generiques&amp;quot;&amp;gt;Génériques&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;ジェネリクスを使用すると、動的な型を持つ再利用可能なコンポーネントを作成できます。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;評価の例：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-typescript hljs&amp;quot; data-lang=&amp;quot;typescript&amp;quot;&amp;gt;const identity = &amp;amp;lt;T&amp;amp;gt;(arg: T): T =&amp;amp;gt; arg;

const output = identity&amp;amp;lt;string&amp;amp;gt;(&amp;quot;hello&amp;quot;);
console.log(output);&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;</description>
        </item><item>
            <title>CSSメモ</title>
            <link >https://cheroliv.com/blog/2023/0062_memo_css_post.html</link>
            <pubDate>Mon, 14 Aug 2023 00:00:00 +0000</pubDate>
            <guid isPermaLink="false">blog/2023/0062_memo_css_post.html</guid>
            <description>&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;toc&amp;quot;&amp;gt;目次&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;olist arabic&amp;quot;&amp;gt;
&amp;lt;ol class=&amp;quot;arabic&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;#good_links&amp;quot;&amp;gt;良いリンク&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;#repo&amp;quot;&amp;gt;レポジトリとコードサンプル&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;#toc_開始&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;underline&amp;quot;&amp;gt;開始 CSS&amp;lt;/span&amp;gt;&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ol&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;good_links&amp;quot;&amp;gt;良いリンク&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;#toc&amp;quot;&amp;gt;目次&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;repo&amp;quot;&amp;gt;レポジトリとコードサンプル&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;GitHub リポジトリ:https://github.com/cheroliv/css-codebase[css-codebase, window = &amp;quot;_blank]&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;toc_開始&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;underline&amp;quot;&amp;gt;開始 CSS&amp;lt;/span&amp;gt;&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;olist arabic&amp;quot;&amp;gt;
&amp;lt;ol class=&amp;quot;arabic&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;#イントロ開始&amp;quot;&amp;gt;[イントロ開始]&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;#開始テキスト&amp;quot;&amp;gt;[開始テキスト]&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;#開始_background&amp;quot;&amp;gt;[開始_background]&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;#開始_ボックス&amp;quot;&amp;gt;[開始_ボックス]&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;#開始_flexbox&amp;quot;&amp;gt;[開始_flexbox]&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;#開始_グリッド&amp;quot;&amp;gt;[開始_グリッド]&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;#開始_絶対_位置&amp;quot;&amp;gt;[開始_絶対_位置]&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;#開始_レスポンシブ&amp;quot;&amp;gt;[開始_レスポンシブ]&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;#開始_結論&amp;quot;&amp;gt;[開始_結論]&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ol&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;#toc&amp;quot;&amp;gt;目次&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;début_intro&amp;quot;&amp;gt;イントロ &amp;amp;amp; セットアップ&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;このビデオに基づくイントロ:&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;videoblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;iframe src=&amp;quot;https://www.youtube.com/embed/iSWjmVcfQGg?rel=0&amp;quot; frameborder=&amp;quot;0&amp;quot; allowfullscreen&amp;gt;&amp;lt;/iframe&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;GitHub リポジトリ:https://github.com/cheroliv/css-codebase/début_css/[css の開始, window = &amp;quot;_blank]&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;メモソース:&amp;lt;br&amp;gt;
index.html&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-html hljs&amp;quot; data-lang=&amp;quot;html&amp;quot;&amp;gt;&amp;amp;lt;!DOCTYPE html&amp;amp;gt;
&amp;amp;lt;html lang=&amp;quot;fr&amp;quot;&amp;amp;gt;
  &amp;amp;lt;head&amp;amp;gt;
    &amp;amp;lt;meta charset=&amp;quot;UTF-8&amp;quot; /&amp;amp;gt;
    &amp;amp;lt;meta http-equiv=&amp;quot;X-UA-Compatible&amp;quot; content=&amp;quot;IE=edge&amp;quot; /&amp;amp;gt;
    &amp;amp;lt;meta name=&amp;quot;viewport&amp;quot; content=&amp;quot;width=device-width, initial-scale=1.0&amp;quot; /&amp;amp;gt;
    &amp;amp;lt;title&amp;amp;gt;Cours CSS&amp;amp;lt;/title&amp;amp;gt;

    &amp;amp;lt;link rel=&amp;quot;stylesheet&amp;quot; href=&amp;quot;style.css&amp;quot; /&amp;amp;gt;
  &amp;amp;lt;/head&amp;amp;gt;
  &amp;amp;lt;body&amp;amp;gt;
    &amp;amp;lt;header&amp;amp;gt;
      &amp;amp;lt;h1&amp;amp;gt;Les bases de CSS&amp;amp;lt;/h1&amp;amp;gt;
    &amp;amp;lt;/header&amp;amp;gt;

    &amp;amp;lt;main&amp;amp;gt;
      &amp;amp;lt;div class=&amp;quot;flexbox&amp;quot;&amp;amp;gt;
        &amp;amp;lt;h2&amp;amp;gt;Flexbox&amp;amp;lt;/h2&amp;amp;gt;
        &amp;amp;lt;ul&amp;amp;gt;
          &amp;amp;lt;li&amp;amp;gt;boite 1&amp;amp;lt;/li&amp;amp;gt;
          &amp;amp;lt;li&amp;amp;gt;boite 2&amp;amp;lt;/li&amp;amp;gt;
          &amp;amp;lt;li&amp;amp;gt;boite 3&amp;amp;lt;/li&amp;amp;gt;
        &amp;amp;lt;/ul&amp;amp;gt;
      &amp;amp;lt;/div&amp;amp;gt;

      &amp;amp;lt;div class=&amp;quot;grid&amp;quot;&amp;amp;gt;
        &amp;amp;lt;h2&amp;amp;gt;Grid&amp;amp;lt;/h2&amp;amp;gt;
        &amp;amp;lt;div class=&amp;quot;grid-container&amp;quot;&amp;amp;gt;
          &amp;amp;lt;img src=&amp;quot;./assets/img/css-logo.png&amp;quot; alt=&amp;quot;logo css&amp;quot; /&amp;amp;gt;

          &amp;amp;lt;form action=&amp;quot;&amp;quot;&amp;amp;gt;
            &amp;amp;lt;input type=&amp;quot;text&amp;quot; id=&amp;quot;firstname&amp;quot; placeholder=&amp;quot;Prénom&amp;quot; /&amp;amp;gt;
            &amp;amp;lt;input type=&amp;quot;text&amp;quot; id=&amp;quot;surname&amp;quot; placeholder=&amp;quot;Nom&amp;quot; /&amp;amp;gt;
            &amp;amp;lt;textarea
              cols=&amp;quot;30&amp;quot;
              rows=&amp;quot;10&amp;quot;
              placeholder=&amp;quot;Ici votre message&amp;quot;
            &amp;amp;gt;&amp;amp;lt;/textarea&amp;amp;gt;
            &amp;amp;lt;input type=&amp;quot;submit&amp;quot; value=&amp;quot;Valider&amp;quot; id=&amp;quot;btn-submit&amp;quot; /&amp;amp;gt;
          &amp;amp;lt;/form&amp;amp;gt;
        &amp;amp;lt;/div&amp;amp;gt;
      &amp;amp;lt;/div&amp;amp;gt;

      &amp;amp;lt;div class=&amp;quot;absolute&amp;quot;&amp;amp;gt;
        &amp;amp;lt;h2&amp;amp;gt;Absolute&amp;amp;lt;/h2&amp;amp;gt;
        &amp;amp;lt;span id=&amp;quot;circle1&amp;quot;&amp;amp;gt;&amp;amp;lt;/span&amp;amp;gt;
        &amp;amp;lt;span id=&amp;quot;circle2&amp;quot;&amp;amp;gt;&amp;amp;lt;/span&amp;amp;gt;
      &amp;amp;lt;/div&amp;amp;gt;
    &amp;amp;lt;/main&amp;amp;gt;
  &amp;amp;lt;/body&amp;amp;gt;
&amp;amp;lt;/html&amp;amp;gt;&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;スタイル.css ファイルを HTML ページにリンクする:&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-html hljs&amp;quot; data-lang=&amp;quot;html&amp;quot;&amp;gt;&amp;amp;lt;/head&amp;amp;gt;
  &amp;amp;lt;link rel=&amp;quot;stylesheet&amp;quot; href=&amp;quot;style.css&amp;quot; /&amp;amp;gt;
&amp;amp;lt;/head&amp;amp;gt;&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;#目次の開始&amp;quot;&amp;gt;[目次の開始]&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;début_texts&amp;quot;&amp;gt;テキスト&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-css hljs&amp;quot; data-lang=&amp;quot;css&amp;quot;&amp;gt;/* import remote de font sur l&amp;#39;ensemble de la feuille*/
@import url(&amp;quot;https://fonts.googleapis.com/css2?family=Oswald:wght@500&amp;amp;amp;display=swap&amp;quot;);

/* import local de font */
@font-face {
  font-family: &amp;quot;DMSerif&amp;quot;;
  src: url(./assets/fonts/DMSerifDisplay-Regular.ttf);
}

/*
body est le parent de toutes les balises,
qu&amp;#39;il contient, donc je le déclare avant,
pour la logique de précédence de parent
*/
body {
  /* si DMSerif n&amp;#39;est pas trouvé alors il se rabat sur Verdana*/
  font-family: &amp;quot;DMSerif&amp;quot;, Verdana;
}

/* va styliser toutes les balises h1,
celles de body sont surchargés,
par la déclaration présente */
h1 {
  text-transform: uppercase;
  /* espacement entre les lettres en pixel*/
  letter-spacing: 3px;
  /* alignement du texte*/
  text-align: center;
  /* Les tailles de polices doivent être en REM  (rem = root em).
  Le REM se base pas sur l&amp;#39;élément parent pour obtenir sa taille mais sur l&amp;#39;élément racine. Ainsi 1rem prendra sa valeur de la font-size de votre document (body ou html).*/
  font-size: 2.5rem;
  /* ombrage du texte */
  text-shadow:
  3px /* offset-x */
  3px /* offset-y */
  8px /* blur-radius */
  #00000042/* color */;
  /* couleur du texte */
  color: #ab0ef4;
  /*attibuer les polices(font): liste, ordonnée par priorité, de polices à utiliser pour mettre en forme le texte de l&amp;#39;élément ciblé.*/
  font-family: &amp;quot;Oswald&amp;quot;, sans-serif;
  /* surligner le text*/
  text-decoration: underline;
}&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;#目次_開始&amp;quot;&amp;gt;[目次_開始]&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;début_background&amp;quot;&amp;gt;背景&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-css hljs&amp;quot; data-lang=&amp;quot;css&amp;quot;&amp;gt;@import url(&amp;quot;https://fonts.googleapis.com/css2?family=Oswald:wght@500&amp;amp;amp;display=swap&amp;quot;);

@font-face {
  font-family: &amp;quot;DMSerif&amp;quot;;
  src: url(./assets/fonts/DMSerifDisplay-Regular.ttf);
}

body {
  font-family: &amp;quot;DMSerif&amp;quot;, Verdana;
  /* image comme background*/
  background: url(./assets/img/bg.jpg) center/cover;
  /* 100VH = 100% de la taille de l&amp;#39;écran (viewport height)
  min afin de ne pas bloquer la possibilité d&amp;#39;avoir un plus grand */
  min-height: 100vh;
}

h1 {
  text-transform: uppercase;
  letter-spacing: 3px;
  text-align: center;
  font-size: 2.5rem;
  text-shadow: 3px 3px 8px #00000042;
  color: #ab0ef4;
  font-family: &amp;quot;Oswald&amp;quot;, sans-serif;
  text-decoration: underline;
}&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;#toc_開始&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;underline&amp;quot;&amp;gt;開始 CSS&amp;lt;/span&amp;gt;&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;開始_boxes&amp;quot;&amp;gt;ボックス (boxes)&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-css hljs&amp;quot; data-lang=&amp;quot;css&amp;quot;&amp;gt;@import url(&amp;quot;https://fonts.googleapis.com/css2?family=Oswald:wght@500&amp;amp;amp;display=swap&amp;quot;);

@font-face {
  font-family: &amp;quot;DMSerif&amp;quot;;
  src: url(./assets/fonts/DMSerifDisplay-Regular.ttf);
}

/* *: létoile donne du style a tous les éléments.
Ensuite remettre un à un les parametres par defaut afin d&amp;#39;eviter les stylisation inattendu.*/
* {
  /* surcharge de base tous les elements à padding 0*/
  margin: 0;
  /* surcharge de base tous les elements à padding 0*/
  padding: 0;
}

body {
  font-family: &amp;quot;DMSerif&amp;quot;, Verdana;
  /* image comme background*/
  background: url(./assets/img/bg.jpg) center/cover;
  min-height: 100vh;
}

h1 {
  text-transform: uppercase;
  letter-spacing: 3px;
  text-align: center;
  font-size: 2.5rem;
  text-shadow: 3px 3px 8px #00000042;
  color: #ab0ef4;
  font-family: &amp;quot;Oswald&amp;quot;, sans-serif;
  text-decoration: underline;
}

main {
  background: rgba(245, 245, 245, 0.9);
  min-height: 500px;
  /* quelque soit la taille de l&amp;#39;écran,
  la boite fait toujours 90% de la taille de la page,
  les 10% restant sont une marge à droite,
  pour avoir 5% de chaque coté on ajoute une margin, tel que [0, auto]*/
  width: 90%;
  /* haut bas prend 0, et  gauche droite prend auto(center cad meme de chaque cotés)*/
  margin: 0 auto;
  /* on ajoute des bords a notre boite*/
  border: 2px solid rgb(0, 140, 255);
  /* on arrondis les coins de la boite*/
  border-radius: 20px 20px 0 0;
  /* ombrage sur la boite*/
  box-shadow: 0px 0px 20px 4px #81cfc6;
  /* marge interrieure de la boite sur tous les cotés*/
  padding: 15px;
}

h2 {
  /* afin de recuprer le comportement par defaut qui a ete surchargé par l&amp;#39;operateur étoile*/
  margin: 0;
}&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-html hljs&amp;quot; data-lang=&amp;quot;html&amp;quot;&amp;gt;&amp;amp;lt;!DOCTYPE html&amp;amp;gt;
&amp;amp;lt;html lang=&amp;quot;fr&amp;quot;&amp;amp;gt;
  &amp;amp;lt;head&amp;amp;gt;
    &amp;amp;lt;meta charset=&amp;quot;UTF-8&amp;quot; /&amp;amp;gt;
    &amp;amp;lt;meta http-equiv=&amp;quot;X-UA-Compatible&amp;quot; content=&amp;quot;IE=edge&amp;quot; /&amp;amp;gt;
    &amp;amp;lt;meta name=&amp;quot;viewport&amp;quot; content=&amp;quot;width=device-width, initial-scale=1.0&amp;quot; /&amp;amp;gt;
    &amp;amp;lt;title&amp;amp;gt;Cours CSS&amp;amp;lt;/title&amp;amp;gt;

    &amp;amp;lt;link rel=&amp;quot;stylesheet&amp;quot; href=&amp;quot;style.css&amp;quot; /&amp;amp;gt;
  &amp;amp;lt;/head&amp;amp;gt;
  &amp;amp;lt;body&amp;amp;gt;
    &amp;amp;lt;header&amp;amp;gt;
      &amp;amp;lt;h1&amp;amp;gt;Les bases de CSS&amp;amp;lt;/h1&amp;amp;gt;
    &amp;amp;lt;/header&amp;amp;gt;

    &amp;amp;lt;main&amp;amp;gt;
      &amp;amp;lt;div class=&amp;quot;flexbox&amp;quot;&amp;amp;gt;
        &amp;amp;lt;h2&amp;amp;gt;Flexbox&amp;amp;lt;/h2&amp;amp;gt;
        &amp;amp;lt;ul&amp;amp;gt;
          &amp;amp;lt;li&amp;amp;gt;boite 1&amp;amp;lt;/li&amp;amp;gt;
          &amp;amp;lt;li&amp;amp;gt;boite 2&amp;amp;lt;/li&amp;amp;gt;
          &amp;amp;lt;li&amp;amp;gt;boite 3&amp;amp;lt;/li&amp;amp;gt;
        &amp;amp;lt;/ul&amp;amp;gt;
      &amp;amp;lt;/div&amp;amp;gt;
    &amp;amp;lt;/main&amp;amp;gt;
  &amp;amp;lt;/body&amp;amp;gt;
&amp;amp;lt;/html&amp;amp;gt;&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;#目次_開始&amp;quot;&amp;gt;[目次_開始]&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;開始_フレックスボックス&amp;quot;&amp;gt;フレックスボックス&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-css hljs&amp;quot; data-lang=&amp;quot;css&amp;quot;&amp;gt;@import url(&amp;quot;https://fonts.googleapis.com/css2?family=Oswald:wght@500&amp;amp;amp;display=swap&amp;quot;);

@font-face {
  font-family: &amp;quot;DMSerif&amp;quot;;
  src: url(./assets/fonts/DMSerifDisplay-Regular.ttf);
}

body {
  font-family: &amp;quot;DMSerif&amp;quot;, Verdana;
  background: url(./assets/img/bg.jpg) center/cover;
  min-height: 100vh;
}

h1 {
  text-transform: uppercase;
  letter-spacing: 3px;
  text-align: center;
  font-size: 2.5rem;
  text-shadow: 3px 3px 8px #00000042;
  color: #ab0ef4;
  font-family: &amp;quot;Oswald&amp;quot;, sans-serif;
  text-decoration: underline;
}

main {
  background: rgba(245, 245, 245, 0.9);
  min-height: 500px;
  width: 90%;
  margin: 0 auto;
  border: 2px solid rgb(0, 140, 255);
  border-radius: 20px 20px 0 0;
  box-shadow: 0px 0px 20px 4px #81cfc6;
  padding: 15px;
}

h2 {
  margin: 0;
}

/* le point permet d&amp;#39;acceder à la classe d&amp;#39;un composant*/
.flexbox {
  border: 2px solid skyblue;
  border-radius: 10px;
  padding: 10px;
  margin-top: 20px;
  min-height: 150px;
}

/* FLEXBOX */
/* Sert à répartir équitablement des éléments sur la page */
.flexbox ul {
  padding: 0;
  /* aligne les éléments enfants de ul(les li)*/
  display: flex;
  /* reparti convenablement(équitablement les li sur la page) */
  justify-content: space-around;
}
/* ce style concerne les li de la classe,
flexbox des balises qui y font referencent*/
.flexbox li {
  /* suprime les boules des éléments de la list li*/
  list-style: none;
  height: 160px;
  width: 160px;
  margin: 10px;
  background: turquoise;
  /* Centrer un unique élément verticalement et horizontalement */
  display: flex;
  justify-content: center;
  align-items: center;
}&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-html hljs&amp;quot; data-lang=&amp;quot;html&amp;quot;&amp;gt;&amp;amp;lt;!DOCTYPE html&amp;amp;gt;
&amp;amp;lt;html lang=&amp;quot;fr&amp;quot;&amp;amp;gt;
  &amp;amp;lt;head&amp;amp;gt;
    &amp;amp;lt;meta charset=&amp;quot;UTF-8&amp;quot; /&amp;amp;gt;
    &amp;amp;lt;meta http-equiv=&amp;quot;X-UA-Compatible&amp;quot; content=&amp;quot;IE=edge&amp;quot; /&amp;amp;gt;
    &amp;amp;lt;meta name=&amp;quot;viewport&amp;quot; content=&amp;quot;width=device-width, initial-scale=1.0&amp;quot; /&amp;amp;gt;
    &amp;amp;lt;title&amp;amp;gt;Cours CSS&amp;amp;lt;/title&amp;amp;gt;

    &amp;amp;lt;link rel=&amp;quot;stylesheet&amp;quot; href=&amp;quot;style.css&amp;quot; /&amp;amp;gt;
  &amp;amp;lt;/head&amp;amp;gt;
  &amp;amp;lt;body&amp;amp;gt;
    &amp;amp;lt;header&amp;amp;gt;
      &amp;amp;lt;h1&amp;amp;gt;Les bases de CSS&amp;amp;lt;/h1&amp;amp;gt;
    &amp;amp;lt;/header&amp;amp;gt;

    &amp;amp;lt;main&amp;amp;gt;
      &amp;amp;lt;div class=&amp;quot;flexbox&amp;quot;&amp;amp;gt;
        &amp;amp;lt;h2&amp;amp;gt;Flexbox&amp;amp;lt;/h2&amp;amp;gt;
        &amp;amp;lt;ul&amp;amp;gt;
          &amp;amp;lt;li&amp;amp;gt;boite 1&amp;amp;lt;/li&amp;amp;gt;
          &amp;amp;lt;li&amp;amp;gt;boite 2&amp;amp;lt;/li&amp;amp;gt;
          &amp;amp;lt;li&amp;amp;gt;boite 3&amp;amp;lt;/li&amp;amp;gt;
        &amp;amp;lt;/ul&amp;amp;gt;
      &amp;amp;lt;/div&amp;amp;gt;
    &amp;amp;lt;/main&amp;amp;gt;
  &amp;amp;lt;/body&amp;amp;gt;
&amp;amp;lt;/html&amp;amp;gt;&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;#目次開始&amp;quot;&amp;gt;[目次開始]&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;début_grid&amp;quot;&amp;gt;グリッド&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;flexbox よりも少し複雑な方法で要素を配置し、グリッド システムなどを用います。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-css hljs&amp;quot; data-lang=&amp;quot;css&amp;quot;&amp;gt;@import url(&amp;quot;https://fonts.googleapis.com/css2?family=Oswald:wght@500&amp;amp;amp;display=swap&amp;quot;);

@font-face {
  font-family: &amp;quot;DMSerif&amp;quot;;
  src: url(./assets/fonts/DMSerifDisplay-Regular.ttf);
}

body {
  font-family: &amp;quot;DMSerif&amp;quot;, Verdana;
  background: url(./assets/img/bg.jpg) center/cover;
  min-height: 100vh;
}

h1 {
  text-transform: uppercase;
  letter-spacing: 3px;
  text-align: center;
  font-size: 2.5rem;
  text-shadow: 3px 3px 8px #00000042;
  color: #ab0ef4;
  font-family: &amp;quot;Oswald&amp;quot;, sans-serif;
  text-decoration: underline;
}

main {
  background: rgba(245, 245, 245, 0.9);
  min-height: 500px;
  width: 90%;
  margin: 0 auto;
  border: 2px solid rgb(0, 140, 255);
  border-radius: 20px 20px 0 0;
  box-shadow: 0px 0px 20px 4px #81cfc6;
  padding: 15px;
}

h2 {
  margin: 0;
}

.flexbox,
.grid {
  border: 2px solid skyblue;
  border-radius: 10px;
  padding: 10px;
  margin-top: 20px;
  min-height: 150px;
}

.flexbox ul {
  padding: 0;
  display: flex;
  justify-content: space-around;
}

.flexbox li {
  list-style: none;
  height: 160px;
  width: 160px;
  margin: 10px;
  background: turquoise;
  display: flex;
  justify-content: center;
  align-items: center;
}

/* GRID */
.grid-container {
  display: grid;
  /* séparatuion de la grille en deux(à ses deux enfants),
  avec à gauche 30% pour l&amp;#39;image
  et à droite 70% pour le formulaire*/
  grid-template-columns: 30% 70%;
}

/* sizing de l&amp;#39;image css-logo
contenu dans la classe grid
qui est dans le parent grid-container*/
.grid img {
  /* l&amp;#39;image remplt 80% de part de grille*/
  width: 80%;
  margin: 20px auto;
  display: block;
}

form {
  display: grid;
  /* deux colonnes de chacune 1 fraction*/
  grid-template-columns: 1fr 1fr;
  /* trois rangés de chacune 1 fraction*/
    grid-template-rows: 1fr 1fr 1fr;
    /* structuration sous forme de template
    de notre repartition des composants
    enfants de la forme*/
  grid-template-areas:
    &amp;quot;i1 i2&amp;quot;/* i1: input1, i2:input2*/
    &amp;quot;ta ta&amp;quot;/*ta: text area */
    &amp;quot;vi bt&amp;quot;/*vi:, bt: bouton */;
}

/* on donne du style sur deux éléments
en meme temps en les listant
avant les parentheses*/
input,
textarea {
  margin: 5px;
  border: 1px solid darkblue;
  padding: 10px;
  font-size: 1.1rem;
  font-family: &amp;quot;DMSerif&amp;quot;;
  border-radius: 5px;
}

/* donner du style uniquement la textearea*/
textarea {
  /* renseigner le nommage pour le grid template area*/
  grid-area: ta;
  height: 40px;
  /* empeche le cassage du style de la page
  en empechant le resizing de la textarea
  du formulaire*/
  resize: none;
}
/* pour pointer un id d&amp;#39;élément html
on utilise la notation préfixe # */
#btn-submit {
  /* renseigner le nommage*/
  grid-area: bt;
  /* change le le symbole de curseur
  souris quand il survole sur le bouton*/
  cursor: pointer;
  background: cyan;
  transition: 0.2s;
}

/* au survole(hover) de la souris
le bouton change de comportement*/
#btn-submit:hover {
  background: darkblue;
  /* couleur de text du bouton devient blanc*/
  color: white;
}&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-html hljs&amp;quot; data-lang=&amp;quot;html&amp;quot;&amp;gt;&amp;amp;lt;!DOCTYPE html&amp;amp;gt;
&amp;amp;lt;html lang=&amp;quot;fr&amp;quot;&amp;amp;gt;

&amp;amp;lt;head&amp;amp;gt;
    &amp;amp;lt;meta charset=&amp;quot;UTF-8&amp;quot; /&amp;amp;gt;
    &amp;amp;lt;meta http-equiv=&amp;quot;X-UA-Compatible&amp;quot; content=&amp;quot;IE=edge&amp;quot; /&amp;amp;gt;
    &amp;amp;lt;meta name=&amp;quot;viewport&amp;quot; content=&amp;quot;width=device-width, initial-scale=1.0&amp;quot; /&amp;amp;gt;
    &amp;amp;lt;title&amp;amp;gt;Cours CSS&amp;amp;lt;/title&amp;amp;gt;

    &amp;amp;lt;link rel=&amp;quot;stylesheet&amp;quot; href=&amp;quot;style.css&amp;quot; /&amp;amp;gt;
&amp;amp;lt;/head&amp;amp;gt;

&amp;amp;lt;body&amp;amp;gt;
    &amp;amp;lt;header&amp;amp;gt;
        &amp;amp;lt;h1&amp;amp;gt;Les bases de CSS&amp;amp;lt;/h1&amp;amp;gt;
    &amp;amp;lt;/header&amp;amp;gt;

    &amp;amp;lt;main&amp;amp;gt;
        &amp;amp;lt;div class=&amp;quot;flexbox&amp;quot;&amp;amp;gt;
            &amp;amp;lt;h2&amp;amp;gt;Flexbox&amp;amp;lt;/h2&amp;amp;gt;
            &amp;amp;lt;ul&amp;amp;gt;
                &amp;amp;lt;li&amp;amp;gt;boite 1&amp;amp;lt;/li&amp;amp;gt;
                &amp;amp;lt;li&amp;amp;gt;boite 2&amp;amp;lt;/li&amp;amp;gt;
                &amp;amp;lt;li&amp;amp;gt;boite 3&amp;amp;lt;/li&amp;amp;gt;
            &amp;amp;lt;/ul&amp;amp;gt;
        &amp;amp;lt;/div&amp;amp;gt;

        &amp;amp;lt;div class=&amp;quot;grid&amp;quot;&amp;amp;gt;
            &amp;amp;lt;h2&amp;amp;gt;Grid&amp;amp;lt;/h2&amp;amp;gt;
            &amp;amp;lt;div class=&amp;quot;grid-container&amp;quot;&amp;amp;gt;
                &amp;amp;lt;img src=&amp;quot;./assets/img/css-logo.png&amp;quot; alt=&amp;quot;logo css&amp;quot; /&amp;amp;gt;

                &amp;amp;lt;form action=&amp;quot;&amp;quot;&amp;amp;gt;
                    &amp;amp;lt;input type=&amp;quot;text&amp;quot; id=&amp;quot;firstname&amp;quot; placeholder=&amp;quot;Prénom&amp;quot; /&amp;amp;gt;
                    &amp;amp;lt;input type=&amp;quot;text&amp;quot; id=&amp;quot;surname&amp;quot; placeholder=&amp;quot;Nom&amp;quot; /&amp;amp;gt;
                    &amp;amp;lt;textarea cols=&amp;quot;30&amp;quot; rows=&amp;quot;10&amp;quot; placeholder=&amp;quot;Ici votre message&amp;quot;&amp;amp;gt;&amp;amp;lt;/textarea&amp;amp;gt;
                    &amp;amp;lt;input type=&amp;quot;submit&amp;quot; value=&amp;quot;Valider&amp;quot; id=&amp;quot;btn-submit&amp;quot; /&amp;amp;gt;
                &amp;amp;lt;/form&amp;amp;gt;
            &amp;amp;lt;/div&amp;amp;gt;
        &amp;amp;lt;/div&amp;amp;gt;
    &amp;amp;lt;/main&amp;amp;gt;
&amp;amp;lt;/body&amp;amp;gt;

&amp;amp;lt;/html&amp;amp;gt;&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;#目次開始&amp;quot;&amp;gt;[目次開始]&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;début_abs_pos&amp;quot;&amp;gt;絶対位置&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-css hljs&amp;quot; data-lang=&amp;quot;css&amp;quot;&amp;gt;@import url(&amp;quot;https://fonts.googleapis.com/css2?family=Oswald:wght@500&amp;amp;amp;display=swap&amp;quot;);

@font-face {
  font-family: &amp;quot;DMSerif&amp;quot;;
  src: url(./assets/fonts/DMSerifDisplay-Regular.ttf);
}

body {
  font-family: &amp;quot;DMSerif&amp;quot;, Verdana;
  background: url(./assets/img/bg.jpg) center/cover;
  min-height: 100vh;
}

h1 {
  text-transform: uppercase;
  letter-spacing: 3px;
  text-align: center;
  font-size: 2.5rem;
  text-shadow: 3px 3px 8px #00000042;
  color: #ab0ef4;
  font-family: &amp;quot;Oswald&amp;quot;, sans-serif;
  text-decoration: underline;
}

main {
  background: rgba(245, 245, 245, 0.9);
  min-height: 500px;
  width: 90%;
  margin: 0 auto;
  border: 2px solid rgb(0, 140, 255);
  border-radius: 20px 20px 0 0;
  box-shadow: 0px 0px 20px 4px #81cfc6;
  padding: 15px;
}

h2 {
  margin: 0;
}

.flexbox,
.grid,
.absolute {
  border: 2px solid skyblue;
  border-radius: 10px;
  padding: 10px;
  margin-top: 20px;
  min-height: 150px;
}

.flexbox ul {
  padding: 0;
  display: flex;
  justify-content: space-around;
}

.flexbox li {
  list-style: none;
  height: 160px;
  width: 160px;
  margin: 10px;
  background: turquoise;
  display: flex;
  justify-content: center;
  align-items: center;
}

.grid-container {
  display: grid;
  grid-template-columns: 30% 70%;
}

.grid img {
  width: 80%;
  margin: 20px auto;
  display: block;
}

form {
  display: grid;
  grid-template-columns: 1fr 1fr;
  grid-template-rows: 1fr 1fr 1fr;
  grid-template-areas: &amp;quot;i1 i2&amp;quot; &amp;quot;ta ta&amp;quot; &amp;quot;vi bt&amp;quot;;
}

input,
textarea {
  margin: 5px;
  border: 1px solid darkblue;
  padding: 10px;
  font-size: 1.1rem;
  font-family: &amp;quot;DMSerif&amp;quot;;
  border-radius: 5px;
}

textarea {
  grid-area: ta;
  height: 40px;
  resize: none;
}

#btn-submit {
  grid-area: bt;
  cursor: pointer;
  background: cyan;
  transition: 0.2s;
}

#btn-submit:hover {
  background: darkblue;
  color: white;
}

/* ABSOLUTE  */
/* Sans élément en Relative, de base, l&amp;#39;élément en absolute l&amp;#39;est par rapport au Body  */
/* Il faut mettre une position relative au parent pour contraindre l&amp;#39;élément en absolute dans ses frontières  */
.absolute {
  /* position relative par rapport à son parent,
  donc contenu dans les frontieres de son parents*/
  position: relative;
}


#circle1 {
  height: 80px;
  width: 80px;
  background: skyblue;
  position: absolute;
  border-radius: 150px;
  top: -20px;
  right: -20px;
}

#circle2 {
  height: 40px;
  width: 40px;
  border-radius: 150px;
  background: teal;
  position: absolute;
  left: 50%;
  transform:
  /*traslate de 50% de la taille du cercle,
  pour etre centré par rapport au centre du cercle,
  plutot que sur son bord gauche par défaut.*/
  translateX(-50%);
  top: 100px;
}&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-html hljs&amp;quot; data-lang=&amp;quot;html&amp;quot;&amp;gt;&amp;amp;lt;!DOCTYPE html&amp;amp;gt;
&amp;amp;lt;html lang=&amp;quot;fr&amp;quot;&amp;amp;gt;

&amp;amp;lt;head&amp;amp;gt;
    &amp;amp;lt;meta charset=&amp;quot;UTF-8&amp;quot; /&amp;amp;gt;
    &amp;amp;lt;meta http-equiv=&amp;quot;X-UA-Compatible&amp;quot; content=&amp;quot;IE=edge&amp;quot; /&amp;amp;gt;
    &amp;amp;lt;meta name=&amp;quot;viewport&amp;quot; content=&amp;quot;width=device-width, initial-scale=1.0&amp;quot; /&amp;amp;gt;
    &amp;amp;lt;title&amp;amp;gt;Cours CSS&amp;amp;lt;/title&amp;amp;gt;

    &amp;amp;lt;link rel=&amp;quot;stylesheet&amp;quot; href=&amp;quot;style.css&amp;quot; /&amp;amp;gt;
&amp;amp;lt;/head&amp;amp;gt;

&amp;amp;lt;body&amp;amp;gt;
    &amp;amp;lt;header&amp;amp;gt;
        &amp;amp;lt;h1&amp;amp;gt;Les bases de CSS&amp;amp;lt;/h1&amp;amp;gt;
    &amp;amp;lt;/header&amp;amp;gt;

    &amp;amp;lt;main&amp;amp;gt;
        &amp;amp;lt;div class=&amp;quot;flexbox&amp;quot;&amp;amp;gt;
            &amp;amp;lt;h2&amp;amp;gt;Flexbox&amp;amp;lt;/h2&amp;amp;gt;
            &amp;amp;lt;ul&amp;amp;gt;
                &amp;amp;lt;li&amp;amp;gt;boite 1&amp;amp;lt;/li&amp;amp;gt;
                &amp;amp;lt;li&amp;amp;gt;boite 2&amp;amp;lt;/li&amp;amp;gt;
                &amp;amp;lt;li&amp;amp;gt;boite 3&amp;amp;lt;/li&amp;amp;gt;
            &amp;amp;lt;/ul&amp;amp;gt;
        &amp;amp;lt;/div&amp;amp;gt;

        &amp;amp;lt;div class=&amp;quot;grid&amp;quot;&amp;amp;gt;
            &amp;amp;lt;h2&amp;amp;gt;Grid&amp;amp;lt;/h2&amp;amp;gt;
            &amp;amp;lt;div class=&amp;quot;grid-container&amp;quot;&amp;amp;gt;
                &amp;amp;lt;img src=&amp;quot;./assets/img/css-logo.png&amp;quot; alt=&amp;quot;logo css&amp;quot; /&amp;amp;gt;

                &amp;amp;lt;form action=&amp;quot;&amp;quot;&amp;amp;gt;
                    &amp;amp;lt;input type=&amp;quot;text&amp;quot; id=&amp;quot;firstname&amp;quot; placeholder=&amp;quot;Prénom&amp;quot; /&amp;amp;gt;
                    &amp;amp;lt;input type=&amp;quot;text&amp;quot; id=&amp;quot;surname&amp;quot; placeholder=&amp;quot;Nom&amp;quot; /&amp;amp;gt;
                    &amp;amp;lt;textarea cols=&amp;quot;30&amp;quot; rows=&amp;quot;10&amp;quot; placeholder=&amp;quot;Ici votre message&amp;quot;&amp;amp;gt;&amp;amp;lt;/textarea&amp;amp;gt;
                    &amp;amp;lt;input type=&amp;quot;submit&amp;quot; value=&amp;quot;Valider&amp;quot; id=&amp;quot;btn-submit&amp;quot; /&amp;amp;gt;
                &amp;amp;lt;/form&amp;amp;gt;
            &amp;amp;lt;/div&amp;amp;gt;
        &amp;amp;lt;/div&amp;amp;gt;

        &amp;amp;lt;div class=&amp;quot;absolute&amp;quot;&amp;amp;gt;
            &amp;amp;lt;h2&amp;amp;gt;Absolute&amp;amp;lt;/h2&amp;amp;gt;
            &amp;amp;lt;span id=&amp;quot;circle1&amp;quot;&amp;amp;gt;&amp;amp;lt;/span&amp;amp;gt;
            &amp;amp;lt;span id=&amp;quot;circle2&amp;quot;&amp;amp;gt;&amp;amp;lt;/span&amp;amp;gt;
        &amp;amp;lt;/div&amp;amp;gt;
    &amp;amp;lt;/main&amp;amp;gt;
&amp;amp;lt;/body&amp;amp;gt;

&amp;amp;lt;/html&amp;amp;gt;&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;#toc_début&amp;quot;&amp;gt;[toc_début]&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;début_responsive&amp;quot;&amp;gt;レスポンシブ&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-css hljs&amp;quot; data-lang=&amp;quot;css&amp;quot;&amp;gt;@import url(&amp;quot;https://fonts.googleapis.com/css2?family=Oswald:wght@500&amp;amp;amp;display=swap&amp;quot;);

@font-face {
  font-family: &amp;quot;DMSerif&amp;quot;;
  src: url(./assets/fonts/DMSerifDisplay-Regular.ttf);
}

body {
  font-family: &amp;quot;DMSerif&amp;quot;, Verdana;
  background: url(./assets/img/bg.jpg) center/cover;
  min-height: 100vh;
}

h1 {
  text-transform: uppercase;
  letter-spacing: 3px;
  text-align: center;
  /* pour etre plus responsive on peut passer la taille en vw(view port width) pour qu&amp;#39;elle s&amp;#39;adapte à la taille de l&amp;#39;ecran*/
  font-size: 2.5rem;
  text-shadow: 3px 3px 8px #00000042;
  color: #ab0ef4;
  font-family: &amp;quot;Oswald&amp;quot;, sans-serif;
  text-decoration: underline;
}

main {
  background: rgba(245, 245, 245, 0.9);
  min-height: 500px;
  width: 90%;
  margin: 0 auto;
  border: 2px solid rgb(0, 140, 255);
  border-radius: 20px 20px 0 0;
  box-shadow: 0px 0px 20px 4px #81cfc6;
  padding: 15px;
}

h2 {
  margin: 0;
}

.flexbox,
.grid,
.absolute {
  border: 2px solid skyblue;
  border-radius: 10px;
  padding: 10px;
  margin-top: 20px;
  min-height: 150px;
}

.flexbox ul {
  padding: 0;
  display: flex;
  justify-content: space-around;
}

.flexbox li {
  list-style: none;
  height: 160px;
  width: 160px;
  margin: 10px;
  background: turquoise;
  display: flex;
  justify-content: center;
  align-items: center;
}

.grid-container {
  display: grid;
  grid-template-columns: 30% 70%;
}

.grid img {
  width: 80%;
  margin: 20px auto;
  /* permet en media query de la centrer en petit écran*/
  display: block;
}

form {
  display: grid;
  grid-template-columns: 1fr 1fr;
  grid-template-rows: 1fr 1fr 1fr;
  grid-template-areas: &amp;quot;i1 i2&amp;quot; &amp;quot;ta ta&amp;quot; &amp;quot;vi bt&amp;quot;;
}

input,
textarea {
  margin: 5px;
  border: 1px solid darkblue;
  padding: 10px;
  font-size: 1.1rem;
  font-family: &amp;quot;DMSerif&amp;quot;;
  border-radius: 5px;
}

textarea {
  grid-area: ta;
  height: 40px;
  resize: none;
}

#btn-submit {
  grid-area: bt;
  cursor: pointer;
  background: cyan;
  transition: 0.2s;
}

#btn-submit:hover {
  background: darkblue;
  color: white;
}

.absolute {
  position: relative;
}


#circle1 {
  height: 80px;
  width: 80px;
  background: skyblue;
  position: absolute;
  border-radius: 150px;
  top: -20px;
  right: -20px;
}

#circle2 {
  height: 40px;
  width: 40px;
  border-radius: 150px;
  background: teal;
  position: absolute;
  left: 50%;
  transform: translateX(-50%);
  top: 100px;
}

/* RESPONSIVE:
a partir des tailles d&amp;#39;ecran permet de surcharger les reglages definis plus haut
*/
@media screen and (max-width: 900px) {
  .grid-container {
    display: block;
  }
  .grid-container img {
    width: 40%;
  }
}

@media screen and (max-width: 610px) {
  .flexbox ul {
    flex-direction: column;
    align-items: center;
  }

  form {
    grid-template-columns: 1fr;
    grid-template-rows: 1fr;
    grid-template-areas:
      &amp;quot;i1&amp;quot;
      &amp;quot;i2&amp;quot;
      &amp;quot;ta&amp;quot;
      &amp;quot;bt&amp;quot;;
  }
  input,
  textarea {
    font-size: 0.8rem;
  }
}&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-html hljs&amp;quot; data-lang=&amp;quot;html&amp;quot;&amp;gt;&amp;amp;lt;!DOCTYPE html&amp;amp;gt;
&amp;amp;lt;html lang=&amp;quot;fr&amp;quot;&amp;amp;gt;

&amp;amp;lt;head&amp;amp;gt;
    &amp;amp;lt;meta charset=&amp;quot;UTF-8&amp;quot; /&amp;amp;gt;
    &amp;amp;lt;meta http-equiv=&amp;quot;X-UA-Compatible&amp;quot; content=&amp;quot;IE=edge&amp;quot; /&amp;amp;gt;
    &amp;amp;lt;meta name=&amp;quot;viewport&amp;quot; content=&amp;quot;width=device-width, initial-scale=1.0&amp;quot; /&amp;amp;gt;
    &amp;amp;lt;title&amp;amp;gt;Cours CSS&amp;amp;lt;/title&amp;amp;gt;

    &amp;amp;lt;link rel=&amp;quot;stylesheet&amp;quot; href=&amp;quot;style.css&amp;quot; /&amp;amp;gt;
&amp;amp;lt;/head&amp;amp;gt;

&amp;amp;lt;body&amp;amp;gt;
    &amp;amp;lt;header&amp;amp;gt;
        &amp;amp;lt;h1&amp;amp;gt;Les bases de CSS&amp;amp;lt;/h1&amp;amp;gt;
    &amp;amp;lt;/header&amp;amp;gt;

    &amp;amp;lt;main&amp;amp;gt;
        &amp;amp;lt;div class=&amp;quot;flexbox&amp;quot;&amp;amp;gt;
            &amp;amp;lt;h2&amp;amp;gt;Flexbox&amp;amp;lt;/h2&amp;amp;gt;
            &amp;amp;lt;ul&amp;amp;gt;
                &amp;amp;lt;li&amp;amp;gt;boite 1&amp;amp;lt;/li&amp;amp;gt;
                &amp;amp;lt;li&amp;amp;gt;boite 2&amp;amp;lt;/li&amp;amp;gt;
                &amp;amp;lt;li&amp;amp;gt;boite 3&amp;amp;lt;/li&amp;amp;gt;
            &amp;amp;lt;/ul&amp;amp;gt;
        &amp;amp;lt;/div&amp;amp;gt;

        &amp;amp;lt;div class=&amp;quot;grid&amp;quot;&amp;amp;gt;
            &amp;amp;lt;h2&amp;amp;gt;Grid&amp;amp;lt;/h2&amp;amp;gt;
            &amp;amp;lt;div class=&amp;quot;grid-container&amp;quot;&amp;amp;gt;
                &amp;amp;lt;img src=&amp;quot;./assets/img/css-logo.png&amp;quot; alt=&amp;quot;logo css&amp;quot; /&amp;amp;gt;

                &amp;amp;lt;form action=&amp;quot;&amp;quot;&amp;amp;gt;
                    &amp;amp;lt;input type=&amp;quot;text&amp;quot; id=&amp;quot;firstname&amp;quot; placeholder=&amp;quot;Prénom&amp;quot; /&amp;amp;gt;
                    &amp;amp;lt;input type=&amp;quot;text&amp;quot; id=&amp;quot;surname&amp;quot; placeholder=&amp;quot;Nom&amp;quot; /&amp;amp;gt;
                    &amp;amp;lt;textarea cols=&amp;quot;30&amp;quot; rows=&amp;quot;10&amp;quot; placeholder=&amp;quot;Ici votre message&amp;quot;&amp;amp;gt;&amp;amp;lt;/textarea&amp;amp;gt;
                    &amp;amp;lt;input type=&amp;quot;submit&amp;quot; value=&amp;quot;Valider&amp;quot; id=&amp;quot;btn-submit&amp;quot; /&amp;amp;gt;
                &amp;amp;lt;/form&amp;amp;gt;
            &amp;amp;lt;/div&amp;amp;gt;
        &amp;amp;lt;/div&amp;amp;gt;

        &amp;amp;lt;div class=&amp;quot;absolute&amp;quot;&amp;amp;gt;
            &amp;amp;lt;h2&amp;amp;gt;Absolute&amp;amp;lt;/h2&amp;amp;gt;
            &amp;amp;lt;span id=&amp;quot;circle1&amp;quot;&amp;amp;gt;&amp;amp;lt;/span&amp;amp;gt;
            &amp;amp;lt;span id=&amp;quot;circle2&amp;quot;&amp;amp;gt;&amp;amp;lt;/span&amp;amp;gt;
        &amp;amp;lt;/div&amp;amp;gt;
    &amp;amp;lt;/main&amp;amp;gt;
&amp;amp;lt;/body&amp;amp;gt;

&amp;amp;lt;/html&amp;amp;gt;&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;#toc_開始&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;underline&amp;quot;&amp;gt;開始 CSS&amp;lt;/span&amp;gt;&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;début_conclusion&amp;quot;&amp;gt;デバッグ &amp;amp;amp; 結論&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-css hljs&amp;quot; data-lang=&amp;quot;css&amp;quot;&amp;gt;/* all elements:
supprime les comportements par défaut*/
* {
  /* les marges à zéro*/
  margin: 0;
  /* les parge internes(padding) à zéro*/
  padding: 0;
  /* tous les bords avec un cadre rouge de 2px.
  qui est ou et qui fait quoi...*/
  border: 2px solid red;
}&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;#目次_開始&amp;quot;&amp;gt;[目次_開始]&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;</description>
        </item><item>
            <title>HTMLメモ</title>
            <link >https://cheroliv.com/blog/2023/0061_memo_html_post.html</link>
            <pubDate>Sun, 13 Aug 2023 00:00:00 +0000</pubDate>
            <guid isPermaLink="false">blog/2023/0061_memo_html_post.html</guid>
            <description>&amp;lt;div id=&amp;quot;toc&amp;quot; class=&amp;quot;toc&amp;quot;&amp;gt;
&amp;lt;div id=&amp;quot;toctitle&amp;quot;&amp;gt;Sommaire&amp;lt;/div&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel1&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_良いリンク&amp;quot;&amp;gt;良いリンク&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_リポジトリとコードサンプル&amp;quot;&amp;gt;リポジトリとコードサンプル&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_良いリンク&amp;quot;&amp;gt;良いリンク&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;html&amp;lt;/div&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;https://htmlcheatsheet.com&amp;quot; target=&amp;quot;&amp;quot;_blank&amp;quot;&amp;gt;htmlcheatsheet.com&amp;lt;/a&amp;gt;: HTMLチートシート&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;フォント&amp;lt;/div&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;https://fontawesome.com&amp;quot;&amp;gt;fontawesome.com&amp;lt;/a&amp;gt;: アイコンライブラリ&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;https://www.toptal.com/designers/htmlarrows/symbols/&amp;quot; target=&amp;quot;&amp;quot;_blank&amp;quot;&amp;gt;toptal.com/designers/htmlarrows/symbols&amp;lt;/a&amp;gt;: HTMLのネイティブアイコン&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;特殊文字とエスケープ&amp;lt;/div&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;https://www.sonarsource.com/blog/encoding-differentials-why-charset-matters/&amp;quot; class=&amp;quot;bare&amp;quot;&amp;gt;https://www.sonarsource.com/blog/encoding-differentials-why-charset-matters/&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;https://stackoverflow.com/a/3614344/13104550&amp;quot; class=&amp;quot;bare&amp;quot;&amp;gt;https://stackoverflow.com/a/3614344/13104550&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;https://html.spec.whatwg.org/multipage/named-characters.html&amp;quot; class=&amp;quot;bare&amp;quot;&amp;gt;https://html.spec.whatwg.org/multipage/named-characters.html&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;#toc&amp;quot;&amp;gt;[toc]&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_リポジトリとコードサンプル&amp;quot;&amp;gt;リポジトリとコードサンプル&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;GitHub リポジトリ:https://github.com/cheroliv/html-codebase[html-codebase, window = &amp;quot;_blank]&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;メモ ソース:&amp;lt;br&amp;gt;
index.html&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-html hljs&amp;quot; data-lang=&amp;quot;html&amp;quot;&amp;gt;&amp;amp;lt;!DOCTYPE html&amp;amp;gt;
&amp;amp;lt;html lang=&amp;quot;fr&amp;quot;&amp;amp;gt;

&amp;amp;lt;head&amp;amp;gt;
  &amp;amp;lt;meta charset=&amp;quot;UTF-8&amp;quot; /&amp;amp;gt;
  &amp;amp;lt;meta name=&amp;quot;viewport&amp;quot; content=&amp;quot;width=device-width, initial-scale=1.0&amp;quot; /&amp;amp;gt;
  &amp;amp;lt;!-- Le titre de la page  --&amp;amp;gt;
  &amp;amp;lt;title&amp;amp;gt;Cours HTML&amp;amp;lt;/title&amp;amp;gt;
  &amp;amp;lt;!-- Icone de l&amp;#39;onglet --&amp;amp;gt;
  &amp;amp;lt;link rel=&amp;quot;shortcut icon&amp;quot; href=&amp;quot;html-logo.png&amp;quot; /&amp;amp;gt;
  &amp;amp;lt;link rel=&amp;quot;stylesheet&amp;quot; href=&amp;quot;https://use.fontawesome.com/releases/v5.8.2/css/all.css&amp;quot; /&amp;amp;gt;
&amp;amp;lt;/head&amp;amp;gt;

&amp;amp;lt;body&amp;amp;gt;
  &amp;amp;lt;header&amp;amp;gt;
    &amp;amp;lt;h1&amp;amp;gt;Texte - Titre H1&amp;amp;lt;/h1&amp;amp;gt;
    &amp;amp;lt;p&amp;amp;gt;
      &amp;amp;lt;em&amp;amp;gt;em pour mettre en italique&amp;amp;lt;/em&amp;amp;gt;,
      &amp;amp;lt;strong&amp;amp;gt;strong pour mettre en gras&amp;amp;lt;/strong&amp;amp;gt;
      &amp;amp;lt;span&amp;amp;gt;L&amp;#39;élement en span ne revient pas à la ligne&amp;amp;lt;/span&amp;amp;gt;.
    &amp;amp;lt;/p&amp;amp;gt;
    &amp;amp;lt;p&amp;amp;gt;
      Lorem ipsum dolor sit amet consectetur adipisicing elit. Exercitationem
      cumque ratione veniam officiis nulla a debitis at facilis sed
      dignissimos.
    &amp;amp;lt;/p&amp;amp;gt;
  &amp;amp;lt;/header&amp;amp;gt;

  &amp;amp;lt;section&amp;amp;gt;
    &amp;amp;lt;div&amp;amp;gt;
      &amp;amp;lt;h2&amp;amp;gt;Photo - Titre H2&amp;amp;lt;/h2&amp;amp;gt;
      &amp;amp;lt;img src=&amp;quot;./img-1.jpg&amp;quot; alt=&amp;quot;image-arbre&amp;quot; height=&amp;quot;200&amp;quot; /&amp;amp;gt;
    &amp;amp;lt;/div&amp;amp;gt;

    &amp;amp;lt;div&amp;amp;gt;
      &amp;amp;lt;h3&amp;amp;gt;Liste - Titre H3&amp;amp;lt;/h3&amp;amp;gt;
      &amp;amp;lt;ul&amp;amp;gt;
        &amp;amp;lt;li&amp;amp;gt;UL = unordered list&amp;amp;lt;/li&amp;amp;gt;
        &amp;amp;lt;li&amp;amp;gt;UL = unordered list&amp;amp;lt;/li&amp;amp;gt;
        &amp;amp;lt;li&amp;amp;gt;UL = unordered list&amp;amp;lt;/li&amp;amp;gt;
      &amp;amp;lt;/ul&amp;amp;gt;
      &amp;amp;lt;ol&amp;amp;gt;
        &amp;amp;lt;li&amp;amp;gt;OL = ordered list&amp;amp;lt;/li&amp;amp;gt;
        &amp;amp;lt;li&amp;amp;gt;OL = ordered list&amp;amp;lt;/li&amp;amp;gt;
        &amp;amp;lt;li&amp;amp;gt;OL = ordered list&amp;amp;lt;/li&amp;amp;gt;
      &amp;amp;lt;/ol&amp;amp;gt;
    &amp;amp;lt;/div&amp;amp;gt;

    &amp;amp;lt;div&amp;amp;gt;
      &amp;amp;lt;h4&amp;amp;gt;Tableaux - Titre H4&amp;amp;lt;/h4&amp;amp;gt;
      &amp;amp;lt;table border=&amp;quot;4&amp;quot; cellpadding=&amp;quot;10&amp;quot; cellspacing=&amp;quot;4&amp;quot; style=&amp;quot;text-align: center&amp;quot;&amp;amp;gt;
        &amp;amp;lt;thead&amp;amp;gt;
          &amp;amp;lt;tr&amp;amp;gt;
            &amp;amp;lt;th&amp;amp;gt;Col 1&amp;amp;lt;/th&amp;amp;gt;
            &amp;amp;lt;th&amp;amp;gt;Col 2&amp;amp;lt;/th&amp;amp;gt;
            &amp;amp;lt;th&amp;amp;gt;Col 3&amp;amp;lt;/th&amp;amp;gt;
          &amp;amp;lt;/tr&amp;amp;gt;
        &amp;amp;lt;/thead&amp;amp;gt;
        &amp;amp;lt;tbody&amp;amp;gt;
          &amp;amp;lt;tr&amp;amp;gt;
            &amp;amp;lt;td rowspan=&amp;quot;2&amp;quot;&amp;amp;gt;Row 1 Cell 1&amp;amp;lt;/td&amp;amp;gt;
            &amp;amp;lt;td&amp;amp;gt;Row 1 Cell 2&amp;amp;lt;/td&amp;amp;gt;
            &amp;amp;lt;td&amp;amp;gt;Row 1 Cell 3&amp;amp;lt;/td&amp;amp;gt;
          &amp;amp;lt;/tr&amp;amp;gt;
          &amp;amp;lt;tr&amp;amp;gt;
            &amp;amp;lt;td&amp;amp;gt;Row 2 Cell 2&amp;amp;lt;/td&amp;amp;gt;
            &amp;amp;lt;td&amp;amp;gt;Row 2 Cell 3&amp;amp;lt;/td&amp;amp;gt;
          &amp;amp;lt;/tr&amp;amp;gt;
          &amp;amp;lt;tr&amp;amp;gt;
            &amp;amp;lt;td colspan=&amp;quot;3&amp;quot;&amp;amp;gt;Row 3 Cell 1&amp;amp;lt;/td&amp;amp;gt;
          &amp;amp;lt;/tr&amp;amp;gt;
        &amp;amp;lt;/tbody&amp;amp;gt;
      &amp;amp;lt;/table&amp;amp;gt;
    &amp;amp;lt;/div&amp;amp;gt;

    &amp;amp;lt;div&amp;amp;gt;
      &amp;amp;lt;h5&amp;amp;gt;&amp;amp;lt;span&amp;amp;gt;&amp;amp;amp;#9814;&amp;amp;lt;/span&amp;amp;gt; Liens - Titre H5&amp;amp;lt;/h5&amp;amp;gt;
      &amp;amp;lt;a href=&amp;quot;https://htmlcheatsheet.com/&amp;quot; target=&amp;quot;_blank&amp;quot;&amp;amp;gt;HTML Cheatsheet&amp;amp;lt;/a&amp;amp;gt;
      &amp;amp;lt;br /&amp;amp;gt;
      &amp;amp;lt;a href=&amp;quot;https://www.toptal.com/designers/htmlarrows/symbols/&amp;quot; target=&amp;quot;_blank&amp;quot;&amp;amp;gt;Icones natifs en HTML&amp;amp;lt;/a&amp;amp;gt;
    &amp;amp;lt;/div&amp;amp;gt;

    &amp;amp;lt;div&amp;amp;gt;
      &amp;amp;lt;h6&amp;amp;gt;&amp;amp;lt;i class=&amp;quot;fas fa-video&amp;quot;&amp;amp;gt;&amp;amp;lt;/i&amp;amp;gt; Vidéo - Titre H6&amp;amp;lt;/h6&amp;amp;gt;
      &amp;amp;lt;video src=&amp;quot;video.mp4&amp;quot; height=&amp;quot;150&amp;quot; autoplay loop muted&amp;amp;gt;&amp;amp;lt;/video&amp;amp;gt;
    &amp;amp;lt;/div&amp;amp;gt;
  &amp;amp;lt;/section&amp;amp;gt;
  &amp;amp;lt;br /&amp;amp;gt;
  &amp;amp;lt;!-- Formulaires en HTML --&amp;amp;gt;
  &amp;amp;lt;section&amp;amp;gt;
    &amp;amp;lt;h2&amp;amp;gt;Formulaire&amp;amp;lt;/h2&amp;amp;gt;
    &amp;amp;lt;form action=&amp;quot;/action.php&amp;quot; method=&amp;quot;post&amp;quot;&amp;amp;gt;
      &amp;amp;lt;label for=&amp;quot;name&amp;quot;&amp;amp;gt;Nom&amp;amp;lt;/label&amp;amp;gt;
      &amp;amp;lt;input id=&amp;quot;name&amp;quot; type=&amp;quot;text&amp;quot; placeholder=&amp;quot;Entrez votre nom&amp;quot; /&amp;amp;gt;&amp;amp;lt;br /&amp;amp;gt;

      &amp;amp;lt;label for=&amp;quot;number&amp;quot;&amp;amp;gt;Entrez votre age&amp;amp;lt;/label&amp;amp;gt;
      &amp;amp;lt;input type=&amp;quot;number&amp;quot; id=&amp;quot;number-age&amp;quot; value=&amp;quot;15&amp;quot; oninput=&amp;quot;document.getElementById(&amp;#39;range-age&amp;#39;).value=this.value&amp;quot;&amp;amp;gt;
      &amp;amp;lt;input type=&amp;quot;range&amp;quot; id=&amp;quot;range-age&amp;quot; min=&amp;quot;0&amp;quot; max=&amp;quot;100&amp;quot;
        oninput=&amp;quot;document.getElementById(&amp;#39;number-age&amp;#39;).value=this.value&amp;quot;&amp;amp;gt;&amp;amp;lt;br /&amp;amp;gt;

      &amp;amp;lt;!-- Input select --&amp;amp;gt;
      &amp;amp;lt;label for=&amp;quot;gender&amp;quot;&amp;amp;gt;Genre&amp;amp;lt;/label&amp;amp;gt;
      &amp;amp;lt;select id=&amp;quot;gender&amp;quot;&amp;amp;gt;
        &amp;amp;lt;option selected=&amp;quot;selected&amp;quot; value=&amp;quot;Homme&amp;quot;&amp;amp;gt;Homme&amp;amp;lt;/option&amp;amp;gt;
        &amp;amp;lt;option value=&amp;quot;Femme&amp;quot;&amp;amp;gt;Femme&amp;amp;lt;/option&amp;amp;gt;
      &amp;amp;lt;/select&amp;amp;gt;&amp;amp;lt;br /&amp;amp;gt;

      &amp;amp;lt;!-- Input radio --&amp;amp;gt;
      &amp;amp;lt;div&amp;amp;gt;
        &amp;amp;lt;input type=&amp;quot;radio&amp;quot; name=&amp;quot;type&amp;quot; id=&amp;quot;human&amp;quot; checked /&amp;amp;gt;
        &amp;amp;lt;label for=&amp;quot;human&amp;quot;&amp;amp;gt;Humain&amp;amp;lt;/label&amp;amp;gt;

        &amp;amp;lt;input type=&amp;quot;radio&amp;quot; name=&amp;quot;type&amp;quot; id=&amp;quot;dog&amp;quot; /&amp;amp;gt;
        &amp;amp;lt;label for=&amp;quot;dog&amp;quot;&amp;amp;gt;Chien&amp;amp;lt;/label&amp;amp;gt;

        &amp;amp;lt;input type=&amp;quot;radio&amp;quot; name=&amp;quot;type&amp;quot; id=&amp;quot;cat&amp;quot; /&amp;amp;gt;
        &amp;amp;lt;label for=&amp;quot;cat&amp;quot;&amp;amp;gt;Chat&amp;amp;lt;/label&amp;amp;gt;
      &amp;amp;lt;/div&amp;amp;gt;

      &amp;amp;lt;textarea cols=&amp;quot;20&amp;quot; rows=&amp;quot;5&amp;quot; placeholder=&amp;quot;Votre message...&amp;quot;&amp;amp;gt;&amp;amp;lt;/textarea&amp;amp;gt;&amp;amp;lt;br /&amp;amp;gt;

      &amp;amp;lt;!-- Input Checkbox --&amp;amp;gt;
      &amp;amp;lt;label&amp;amp;gt;&amp;amp;lt;input type=&amp;quot;checkbox&amp;quot; /&amp;amp;gt;Accepter les CGV&amp;amp;lt;/label&amp;amp;gt; &amp;amp;lt;br /&amp;amp;gt;
      &amp;amp;lt;input type=&amp;quot;submit&amp;quot; value=&amp;quot;Submit&amp;quot; /&amp;amp;gt;
    &amp;amp;lt;/form&amp;amp;gt;
  &amp;amp;lt;/section&amp;amp;gt;
  &amp;amp;lt;br /&amp;amp;gt;
  &amp;amp;lt;!-- Mail &amp;amp;amp; envoi de fichiers --&amp;amp;gt;
  &amp;amp;lt;footer&amp;amp;gt;
    &amp;amp;lt;a href=&amp;quot;mailto:fs@gmail.com&amp;quot;&amp;amp;gt;Ecrivez-moi !&amp;amp;lt;/a&amp;amp;gt;
    &amp;amp;lt;br /&amp;amp;gt;
    &amp;amp;lt;a href=&amp;quot;notice.txt&amp;quot; download=&amp;quot;nom-du-fichier&amp;quot;&amp;amp;gt;Télécharger la notice&amp;amp;lt;/a&amp;amp;gt;
    &amp;amp;lt;details&amp;amp;gt;
      &amp;amp;lt;summary&amp;amp;gt;Plus d&amp;#39;infos&amp;amp;lt;/summary&amp;amp;gt;
      &amp;amp;lt;p&amp;amp;gt;
        Lorem ipsum dolor, sit amet consectetur adipisicing elit. Harum,
        repellendus.
      &amp;amp;lt;/p&amp;amp;gt;
    &amp;amp;lt;/details&amp;amp;gt;
  &amp;amp;lt;/footer&amp;amp;gt;
&amp;amp;lt;/body&amp;amp;gt;

&amp;amp;lt;/html&amp;amp;gt;&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;#toc&amp;quot;&amp;gt;[toc]&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;</description>
        </item><item>
            <title>メモ JavaScript</title>
            <link >https://cheroliv.com/blog/2023/0060_memo_js_post.html</link>
            <pubDate>Fri, 4 Aug 2023 00:00:00 +0000</pubDate>
            <guid isPermaLink="false">blog/2023/0060_memo_js_post.html</guid>
            <description>&amp;lt;div id=&amp;quot;preamble&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;githubリポジトリ:https://github.com/cheroliv/js-codebase[js-codebase, window=&amp;quot;_blank]&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;toc_js&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;underline&amp;quot;&amp;gt;Intro Javascript&amp;lt;/span&amp;gt;&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;olist arabic&amp;quot;&amp;gt;
&amp;lt;ol class=&amp;quot;arabic&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;#start&amp;quot;&amp;gt;変数, 算術演算子 と 文字列&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;#arrays&amp;quot;&amp;gt;配列&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;#functions&amp;quot;&amp;gt;関数&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;#param_x_scope&amp;quot;&amp;gt;パラメータとスコープ&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;#objects&amp;quot;&amp;gt;オブジェクト&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;#ループ&amp;quot;&amp;gt;[ループ]&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;#const_var_let&amp;quot;&amp;gt;Const、varおよびlet&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;#rest_and_spread_operators&amp;quot;&amp;gt;Rest と spread operators&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;#分解&amp;quot;&amp;gt;[分解]&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;#import_export&amp;quot;&amp;gt;モジュールのインポートとエクスポート&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;#classes&amp;quot;&amp;gt;クラスの使用&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ol&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;index.html&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-html hljs&amp;quot; data-lang=&amp;quot;html&amp;quot;&amp;gt;&amp;amp;lt;!DOCTYPE html&amp;amp;gt;
&amp;amp;lt;html lang=&amp;quot;fr&amp;quot;&amp;amp;gt;

&amp;amp;lt;head&amp;amp;gt;
    &amp;amp;lt;meta charset=&amp;quot;UTF-8&amp;quot;&amp;amp;gt;
    &amp;amp;lt;title&amp;amp;gt;Document&amp;amp;lt;/title&amp;amp;gt;
    &amp;amp;lt;meta name=&amp;quot;viewport&amp;quot; content=&amp;quot;width=device-width, initial-scale=1.0&amp;quot; /&amp;amp;gt;
    &amp;amp;lt;meta http-equiv=&amp;quot;X-UA-Compatible&amp;quot; content=&amp;quot;ie=edge&amp;quot; /&amp;amp;gt;
&amp;amp;lt;/head&amp;amp;gt;

&amp;amp;lt;body&amp;amp;gt;
    index
    &amp;amp;lt;script src=&amp;quot;01_start.js&amp;quot;&amp;amp;gt;&amp;amp;lt;/script&amp;amp;gt;
    &amp;amp;lt;script src=&amp;quot;02_arrays.js&amp;quot;&amp;amp;gt;&amp;amp;lt;/script&amp;amp;gt;
    &amp;amp;lt;script src=&amp;quot;03_functions.js&amp;quot;&amp;amp;gt;&amp;amp;lt;/script&amp;amp;gt;
    &amp;amp;lt;script src=&amp;quot;04_param_x_scope.js&amp;quot;&amp;amp;gt;&amp;amp;lt;/script&amp;amp;gt;
    &amp;amp;lt;script src=&amp;quot;05_objects.js&amp;quot;&amp;amp;gt;&amp;amp;lt;/script&amp;amp;gt;
    &amp;amp;lt;script src=&amp;quot;06_loops.js&amp;quot;&amp;amp;gt;&amp;amp;lt;/script&amp;amp;gt;
    &amp;amp;lt;script src=&amp;quot;07_const_var_let.js&amp;quot;&amp;amp;gt;&amp;amp;lt;/script&amp;amp;gt;
    &amp;amp;lt;script src=&amp;quot;08_rest_and_spread_operators.js&amp;quot;&amp;amp;gt;&amp;amp;lt;/script&amp;amp;gt;
    &amp;amp;lt;script src=&amp;quot;09_destructuring.js&amp;quot;&amp;amp;gt;&amp;amp;lt;/script&amp;amp;gt;
    &amp;amp;lt;script src=&amp;quot;10_module_import_export.js&amp;quot;&amp;amp;gt;&amp;amp;lt;/script&amp;amp;gt;
&amp;amp;lt;/body&amp;amp;gt;

&amp;amp;lt;/html&amp;amp;gt;&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;#toc_js&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;underline&amp;quot;&amp;gt;Intro Javascript&amp;lt;/span&amp;gt;&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;start&amp;quot;&amp;gt;変数, 算術演算子 と 文字列&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;01_start.js&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-javascript hljs&amp;quot; data-lang=&amp;quot;javascript&amp;quot;&amp;gt;/**
 * Variables
 */
//une variable stupide
var my_variable = &amp;quot;dummy variable&amp;quot;;
console.log(my_variable);

//assertion
console.assert(my_variable === &amp;quot;dummy variable&amp;quot;);

var username = &amp;quot;cheroliv&amp;quot;;
console.log(username);
console.assert(username === &amp;quot;cheroliv&amp;quot;);

//concaténation de string
console.assert(username === &amp;quot;cher&amp;quot; + &amp;quot;oliv&amp;quot;);

/**
 *  Opérateur arithmétique: + - * / %
 */
//integer
var x = 10;
var y = 5;
var z = 20;

console.log(x + y);
console.assert(x + y === 15);

console.log(x + y - z);
console.assert(x + y - z === -5);


console.log(x - y);
console.assert(x - y === 5);


console.log(x * y);
console.assert(x * y === 50);

console.log(x / y);
console.assert(x / y === 2);


console.log(&amp;quot;---------&amp;quot;);

x = 20;
y = 10;

console.log(x + y);
console.assert(x + y === 30);

console.log(x + y - z);
console.assert(x + y - z === 10);


console.log(x - y);
console.assert(x - y === 10);

console.log(x * y);
console.assert(x * y === 200);

console.log(x / z);
console.assert(x / z === 1);


//Littéraux de gabarits pour string avec backstick `
//Template literals (Template strings)
console.assert(`typeof z: ${typeof z}` === &amp;quot;typeof z: number&amp;quot;);

console.log(`x is type of : ${typeof x}`);
console.log(`y is type of : ${typeof y}`);
console.log(`z is type of : ${typeof z}`);

//typeof: donne le type de la variable
console.assert(typeof x === &amp;quot;number&amp;quot;);
console.assert(typeof y === &amp;quot;number&amp;quot;);
console.assert(typeof z === &amp;quot;number&amp;quot;);


console.log(&amp;quot;---------&amp;quot;);
/**
 * Incrémenation/décrémentation
 */
//incrémantation/décrémentation préfixe
console.log(++x) //incrémenté puis affiché: 21
console.log(x) //la valeur incrémenté: 21

//incrémantation/décrémentation suffixe
console.log(y++) //affiche la valeur sans incrémenation puis incrémente: 10
console.log(y) //la valeur incrémenté: 11

//décrémentation
x--;
y--;
console.assert(x === 20);
console.assert(y === 10);


/**
 * String: chaine de caractères
 */
console.log(`username: ${username}`);

//taille de la string
console.log(`username.length: ${username.length}`);
console.assert(username.length === 8);
console.assert(username.length === &amp;quot;cheroliv&amp;quot;.length);
console.log(&amp;quot;---------&amp;quot;);&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;#toc_js&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;underline&amp;quot;&amp;gt;Intro Javascript&amp;lt;/span&amp;gt;&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;arrays&amp;quot;&amp;gt;配列&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;02_arrays.js&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-javascript hljs&amp;quot; data-lang=&amp;quot;javascript&amp;quot;&amp;gt;/**
 * Les arrays
 */
// auteurs [[&amp;quot;nom &amp;quot;, &amp;quot;prénom&amp;quot;, &amp;quot;pays&amp;quot;]]
var writers = [
    [&amp;quot;Karl&amp;quot;, &amp;quot;Marx&amp;quot;, &amp;quot;de&amp;quot;],
    [&amp;quot;Jean-Jacques&amp;quot;, &amp;quot;Rousseau&amp;quot;, &amp;quot;fr&amp;quot;],
    [&amp;quot;Victor&amp;quot;, &amp;quot;Hugo&amp;quot;, &amp;quot;fr&amp;quot;],
    [&amp;quot;René&amp;quot;, &amp;quot;Descartes&amp;quot;, &amp;quot;fr&amp;quot;],
    [&amp;quot;Paul&amp;quot;, &amp;quot;Verlaine&amp;quot;, &amp;quot;fr&amp;quot;],
    [&amp;quot;Antonio&amp;quot;, &amp;quot;Gramsci&amp;quot;, &amp;quot;it&amp;quot;],
    [&amp;quot;Georg&amp;quot;, &amp;quot;Lukacs&amp;quot;, &amp;quot;hu&amp;quot;],
    [&amp;quot;Franz&amp;quot;, &amp;quot;Kafka&amp;quot;, &amp;quot;hu&amp;quot;],
    [&amp;quot;Arthur&amp;quot;, &amp;quot;Rimbaud&amp;quot;, &amp;quot;fr&amp;quot;],
    [&amp;quot;Gérard&amp;quot;, &amp;quot;de Nerval&amp;quot;, &amp;quot;fr&amp;quot;],
    [&amp;quot;Chrétien&amp;quot;, &amp;quot;de Troyes&amp;quot;, &amp;quot;fr&amp;quot;],
    [&amp;quot;François&amp;quot;, &amp;quot;Rabelais&amp;quot;, &amp;quot;fr&amp;quot;],
    [&amp;quot;Georg&amp;quot;, &amp;quot;Hegel&amp;quot;, &amp;quot;de&amp;quot;],
    [&amp;quot;Friedrich&amp;quot;, &amp;quot;Engels&amp;quot;, &amp;quot;de&amp;quot;],
]

console.table(writers);

// accés aux élèments du tableau
console.log(writers[0]);
console.log(`${writers[0][0]}, ${writers[0][1]} (${writers[0][2]})`);
console.assert(&amp;quot;Karl, Marx (de)&amp;quot; === `${writers[0][0]}, ${writers[0][1]} (${writers[0][2]})`);

//sauvegarder la valeur du prénom de Marx
var karl = writers[0][0]

//éditer un élement du tableau, le prénom de Marx
writers[0][0] = &amp;quot;Karlito&amp;quot;

console.log(`${writers[0][0]}, ${writers[0][1]} (${writers[0][2]})`);
console.assert(&amp;quot;Karlito, Marx (de)&amp;quot; === `${writers[0][0]}, ${writers[0][1]} (${writers[0][2]})`);

console.assert(&amp;quot;Karl&amp;quot; === karl);

//remettre la valeur initale du prénom de Marx
writers[0][0] = karl;

console.assert(`${karl}, Marx (de)` === `${writers[0][0]}, ${writers[0][1]} (${writers[0][2]})`);

console.log(&amp;quot;---------&amp;quot;);

/**
 *  Arrays: map/forEach/pop/push/slice/sort/shift/unshift
 */

var numbers = [1, 5, 4, 3, 2];

console.log(&amp;quot;Iterate with forEach&amp;quot;);
// parcourir avec array.forEach
numbers.forEach((it) =&amp;amp;gt; console.log(it));
console.log(&amp;quot;---------&amp;quot;);

console.log(&amp;quot;Iterate with map&amp;quot;);
// parcourir avec array.map
numbers.map((it) =&amp;amp;gt; console.log(it));
console.log(&amp;quot;---------&amp;quot;);

//afficher les éléments sur une ligne
//génère la string avec le formatage des nombres
const numbersString = (numberArray) =&amp;amp;gt; {
    var consoleOutput = new String();
    numberArray.forEach(number =&amp;amp;gt; consoleOutput += `${number}, `);
    return consoleOutput = consoleOutput.substring(0, consoleOutput.length - 2);
};

//affiche la chaine entre crochets dans la console
const displayNumbers = (numbersStr) =&amp;amp;gt; {
    console.log(`[${numbersString(numbersStr)}]`);
};

console.log(&amp;quot;orginal number array&amp;quot;)
displayNumbers(numbers);
console.log(&amp;quot;---------&amp;quot;);


//push: ajoute à la fin
console.log(&amp;quot;push&amp;quot;);
numbers.push(6);
displayNumbers(numbers);
console.log(&amp;quot;---------&amp;quot;);

//pop: suprime le dernier
console.log(&amp;quot;pop&amp;quot;);
numbers.pop();
displayNumbers(numbers);
console.log(&amp;quot;---------&amp;quot;);

//unshift: ajouter le parametre au debut de l&amp;#39;array
console.log(&amp;quot;unshift&amp;quot;);
numbers.unshift(0);
displayNumbers(numbers);
console.log(&amp;quot;---------&amp;quot;);

//shift: supprime le premier element de l&amp;#39;array
console.log(&amp;quot;shift&amp;quot;);
numbers.shift();
displayNumbers(numbers);
console.log(&amp;quot;---------&amp;quot;);

//slice: renvoi l&amp;#39;array entre les positions en argument
console.log(&amp;quot;slice&amp;quot;);
var sliceNumbersResult = numbers.slice(2, 4);
displayNumbers(sliceNumbersResult);
console.log(&amp;quot;---------&amp;quot;);

//sort asc
console.log(&amp;quot;sort asc&amp;quot;);
var ascSort = numbers.sort((a, b) =&amp;amp;gt; a - b);
displayNumbers(ascSort);
console.log(&amp;quot;---------&amp;quot;);

//sort desc
console.log(&amp;quot;sort desc&amp;quot;);
var descSort = numbers.sort((a, b) =&amp;amp;gt; b - a);
displayNumbers(descSort);
console.log(&amp;quot;---------&amp;quot;);&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;#toc_js&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;underline&amp;quot;&amp;gt;Intro Javascript&amp;lt;/span&amp;gt;&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;functions&amp;quot;&amp;gt;関数&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;03_functions.js&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-javascript hljs&amp;quot; data-lang=&amp;quot;javascript&amp;quot;&amp;gt;/**
 *  Les fonctions
 */

//function style legacy
function sayHelloWorldLegacy() {
    console.log(&amp;quot;Hello world legacy!&amp;quot;);
}
sayHelloWorldLegacy();

function sayHelloLegacy(firstName, lastName, style) {
    console.log(`Hello ${firstName}, ${lastName} (${style})`);
}
sayHelloLegacy(&amp;quot;Cher&amp;quot;, &amp;quot;Oliv&amp;quot;, &amp;quot;legacy&amp;quot;);

console.log(&amp;quot;---------&amp;quot;);

//function style arrow
const sayHelloWorld = () =&amp;amp;gt; console.log(&amp;quot;Hello world!&amp;quot;);
sayHelloWorld();

const sayHello = (firstName, lastName) =&amp;amp;gt;
    console.log(`Hello ${firstName}, ${lastName}`);
sayHello(&amp;quot;Cher&amp;quot;, &amp;quot;Oliv&amp;quot;);

console.log(&amp;quot;---------&amp;quot;);

var authors = [
    [&amp;quot;Chrétien&amp;quot;, &amp;quot;de Troyes&amp;quot;, &amp;quot;fr&amp;quot;],
    [&amp;quot;François&amp;quot;, &amp;quot;Rabelais&amp;quot;, &amp;quot;fr&amp;quot;],
    [&amp;quot;René&amp;quot;, &amp;quot;Descartes&amp;quot;, &amp;quot;fr&amp;quot;],
    [&amp;quot;Jean-Jacques&amp;quot;, &amp;quot;Rousseau&amp;quot;, &amp;quot;fr&amp;quot;],
    [&amp;quot;Georg&amp;quot;, &amp;quot;Hegel&amp;quot;, &amp;quot;de&amp;quot;],
    [&amp;quot;Karl&amp;quot;, &amp;quot;Marx&amp;quot;, &amp;quot;de&amp;quot;],
    [&amp;quot;Friedrich&amp;quot;, &amp;quot;Engels&amp;quot;, &amp;quot;de&amp;quot;],
    [&amp;quot;Victor&amp;quot;, &amp;quot;Hugo&amp;quot;, &amp;quot;fr&amp;quot;],
    [&amp;quot;Paul&amp;quot;, &amp;quot;Verlaine&amp;quot;, &amp;quot;fr&amp;quot;],
    [&amp;quot;Antonio&amp;quot;, &amp;quot;Gramsci&amp;quot;, &amp;quot;it&amp;quot;],
    [&amp;quot;Georg&amp;quot;, &amp;quot;Lukacs&amp;quot;, &amp;quot;hu&amp;quot;],
    [&amp;quot;Franz&amp;quot;, &amp;quot;Kafka&amp;quot;, &amp;quot;hu&amp;quot;],
    [&amp;quot;Arthur&amp;quot;, &amp;quot;Rimbaud&amp;quot;, &amp;quot;fr&amp;quot;],
    [&amp;quot;Gérard&amp;quot;, &amp;quot;de Nerval&amp;quot;, &amp;quot;fr&amp;quot;],
]


const displayAuthors = (authorsArray) =&amp;amp;gt; authorsArray.forEach(author =&amp;amp;gt;
    console.log(`${author[0]} ${author[1]}, (${author[2]})`)
);

displayAuthors(authors);

console.log(&amp;quot;---------&amp;quot;);

/**
 * valeur par défaut des parametres d&amp;#39;une fonctions
 */
const add = (a = 0, b = 0) =&amp;amp;gt; a + b;
console.assert(add() === 0)
console.assert(add(1) === 1)
console.assert(add(1, 1) === 2)

console.log(&amp;quot;---------&amp;quot;);&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;#toc_js&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;underline&amp;quot;&amp;gt;Intro Javascript&amp;lt;/span&amp;gt;&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;param_x_scope&amp;quot;&amp;gt;パラメータとスコープ&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;04_param_x_scope.js&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-javascript hljs&amp;quot; data-lang=&amp;quot;javascript&amp;quot;&amp;gt;//global scope: visible partout, dans et hors functions
var global;

const foo = () =&amp;amp;gt; {
    //local scope: visible uniquement dans la fonction foo
    var bar = &amp;quot;bar&amp;quot;
    console.log(bar)
}

foo();
console.log(&amp;quot;---------&amp;quot;);&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;#toc_js&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;underline&amp;quot;&amp;gt;Intro Javascript&amp;lt;/span&amp;gt;&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;objects&amp;quot;&amp;gt;オブジェクト&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;05_objects.js&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-javascript hljs&amp;quot; data-lang=&amp;quot;javascript&amp;quot;&amp;gt;/**
 * Les objects
 */
var authors = [
    [&amp;quot;Chrétien&amp;quot;, &amp;quot;de Troyes&amp;quot;, &amp;quot;fr&amp;quot;],
    [&amp;quot;François&amp;quot;, &amp;quot;Rabelais&amp;quot;, &amp;quot;fr&amp;quot;],
    [&amp;quot;René&amp;quot;, &amp;quot;Descartes&amp;quot;, &amp;quot;fr&amp;quot;],
    [&amp;quot;Jean-Jacques&amp;quot;, &amp;quot;Rousseau&amp;quot;, &amp;quot;fr&amp;quot;],
    [&amp;quot;Georg&amp;quot;, &amp;quot;Hegel&amp;quot;, &amp;quot;de&amp;quot;],
    [&amp;quot;Karl&amp;quot;, &amp;quot;Marx&amp;quot;, &amp;quot;de&amp;quot;],
    [&amp;quot;Friedrich&amp;quot;, &amp;quot;Engels&amp;quot;, &amp;quot;de&amp;quot;],
    [&amp;quot;Victor&amp;quot;, &amp;quot;Hugo&amp;quot;, &amp;quot;fr&amp;quot;],
    [&amp;quot;Paul&amp;quot;, &amp;quot;Verlaine&amp;quot;, &amp;quot;fr&amp;quot;],
    [&amp;quot;Antonio&amp;quot;, &amp;quot;Gramsci&amp;quot;, &amp;quot;it&amp;quot;],
    [&amp;quot;Georg&amp;quot;, &amp;quot;Lukacs&amp;quot;, &amp;quot;hu&amp;quot;],
    [&amp;quot;Franz&amp;quot;, &amp;quot;Kafka&amp;quot;, &amp;quot;hu&amp;quot;],
    [&amp;quot;Arthur&amp;quot;, &amp;quot;Rimbaud&amp;quot;, &amp;quot;fr&amp;quot;],
    [&amp;quot;Gérard&amp;quot;, &amp;quot;de Nerval&amp;quot;, &amp;quot;fr&amp;quot;],
];

var hugo = {
    firstName: authors[7][0],
    lastName: authors[7][1],
    country: authors[7][2],
};

var book = {
    author: hugo,
    title: &amp;quot;Les misérables&amp;quot;
};
console.log(hugo);
console.log(book);

//accéder à un membre de l&amp;#39;objet par point
console.log(hugo.country);

//accéder à un membre de l&amp;#39;objet par crochet
console.log(book[&amp;quot;title&amp;quot;]);

console.log(book.author.lastName);

console.log(book[&amp;quot;author&amp;quot;][&amp;quot;firstName&amp;quot;]);

//ajouter une clé a un objet
hugo.gender = &amp;quot;non binary&amp;quot;;
console.assert(hugo.gender === &amp;quot;non binary&amp;quot;);


//mettre à jour une clé
hugo.gender = &amp;quot;male&amp;quot;;
console.assert(hugo.gender !== &amp;quot;non binary&amp;quot;);
console.assert(hugo[&amp;quot;gender&amp;quot;] === &amp;quot;male&amp;quot;);

//supprimer une clé
delete hugo.gender;


//verfier que l&amp;#39;objet ne contient pas la clé gender
console.assert(!Object.keys(hugo).includes(&amp;quot;gender&amp;quot;));


console.log(&amp;quot;---------&amp;quot;);&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;#toc_js&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;underline&amp;quot;&amp;gt;Intro Javascript&amp;lt;/span&amp;gt;&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;loops&amp;quot;&amp;gt;ループ&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;06_loops.js&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-javascript hljs&amp;quot; data-lang=&amp;quot;javascript&amp;quot;&amp;gt;/**
 * Les boucles: Itérer sur arrays et objets.
 */

console.log(&amp;quot;for loop over array&amp;quot;);

var numbers = [12, 10, 8, 6, 4, 2, 0];

for (number of numbers) {
    console.log(number);
}

console.log(&amp;quot;---------&amp;quot;);

console.log(&amp;quot;for loop over object key&amp;quot;);

var obj = { a: 1, b: 2, c: 3, d: 4 };

for (key in obj) {
    console.log(key);
}

console.log(&amp;quot;---------&amp;quot;);

console.log(&amp;quot;for loop over object value&amp;quot;);

for (value in obj) {
    console.log(obj[value]);
}

console.log(&amp;quot;---------&amp;quot;);

console.log(&amp;quot;another for loop over authors array&amp;quot;)

var authors = [
    [&amp;quot;Chrétien&amp;quot;, &amp;quot;de Troyes&amp;quot;, &amp;quot;fr&amp;quot;],
    [&amp;quot;François&amp;quot;, &amp;quot;Rabelais&amp;quot;, &amp;quot;fr&amp;quot;],
    [&amp;quot;René&amp;quot;, &amp;quot;Descartes&amp;quot;, &amp;quot;fr&amp;quot;],
    [&amp;quot;Jean-Jacques&amp;quot;, &amp;quot;Rousseau&amp;quot;, &amp;quot;fr&amp;quot;],
    [&amp;quot;Georg&amp;quot;, &amp;quot;Hegel&amp;quot;, &amp;quot;de&amp;quot;],
    [&amp;quot;Karl&amp;quot;, &amp;quot;Marx&amp;quot;, &amp;quot;de&amp;quot;],
    [&amp;quot;Friedrich&amp;quot;, &amp;quot;Engels&amp;quot;, &amp;quot;de&amp;quot;],
    [&amp;quot;Victor&amp;quot;, &amp;quot;Hugo&amp;quot;, &amp;quot;fr&amp;quot;],
    [&amp;quot;Paul&amp;quot;, &amp;quot;Verlaine&amp;quot;, &amp;quot;fr&amp;quot;],
    [&amp;quot;Antonio&amp;quot;, &amp;quot;Gramsci&amp;quot;, &amp;quot;it&amp;quot;],
    [&amp;quot;Georg&amp;quot;, &amp;quot;Lukacs&amp;quot;, &amp;quot;hu&amp;quot;],
    [&amp;quot;Franz&amp;quot;, &amp;quot;Kafka&amp;quot;, &amp;quot;hu&amp;quot;],
    [&amp;quot;Arthur&amp;quot;, &amp;quot;Rimbaud&amp;quot;, &amp;quot;fr&amp;quot;],
    [&amp;quot;Gérard&amp;quot;, &amp;quot;de Nerval&amp;quot;, &amp;quot;fr&amp;quot;],
];

for (const [i, value] of authors.entries()) {
    console.log(`${value[0]}, ${value[1]} (${value[2]})`);
}

console.log(&amp;quot;---------&amp;quot;);

console.log(&amp;quot;while loop over array&amp;quot;)

var i = 0
while (i &amp;amp;lt; authors.length) {
    console.log(`${authors[i][0]}, ${authors[i][1]} (${authors[i][2]})`);
    i++;
}

console.log(&amp;quot;---------&amp;quot;);&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;#toc_js&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;underline&amp;quot;&amp;gt;Intro Javascript&amp;lt;/span&amp;gt;&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;const_var_let&amp;quot;&amp;gt;Const、varおよびlet&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;07_const_var_let.js&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-javascript hljs&amp;quot; data-lang=&amp;quot;javascript&amp;quot;&amp;gt;/**
 * const X var X let
 */
//var x du if n&amp;#39;est pas confiné au scope du if
const varTest = () =&amp;amp;gt; {
    var x = 1;
    console.log(x);
    console.assert(x === 1);
    if (true) {
        var x = 2;
        console.log(x);
        console.assert(x === 2);
    }
    console.log(x);
    console.assert(x !== 1);
    console.assert(x === 2);
}
varTest();

console.log(&amp;quot;---------&amp;quot;);

//var x est global à tous les fichier js
//chargés dans la page html
//var x issue du fichier 1_start.js
//ligne 46
console.log(x);
console.assert(x === 20);

console.log(&amp;quot;---------&amp;quot;);

//premier let x est confiné au scope de la fonction
//le let x du if est confiné au scope du if
const letTest = () =&amp;amp;gt; {
    let x = 1;
    console.log(x);
    console.assert(x === 1);
    if (true) {
        let x = 2;
        console.log(x);
        console.assert(x === 2);
    }
    console.log(x);
    console.assert(x === 1);
    console.assert(x !== 2);
}
letTest();

console.log(&amp;quot;---------&amp;quot;);

/**
 * const: déclare un emplacement mémoire non réattribuable
 * c&amp;#39;est modifiable pour un array,
 * mais non réinitialisable;
 * ex:
 * const arr = [25, 27, 29]
 * arr = [5, 7] //impossible
 * arr[0]=20 // possible
 * ex:
 * const n = 1;
 * n = 3; //impossible
 */
const arr = [25, 27, 29]
console.table(arr);
arr[0] = 20 // possible
console.table(arr);

arr.pop()
console.table(arr);
console.log(&amp;quot;---------&amp;quot;);&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;#toc_js&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;underline&amp;quot;&amp;gt;Intro Javascript&amp;lt;/span&amp;gt;&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;rest_and_spread_operators&amp;quot;&amp;gt;Rest と spread operators&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;08_rest_and_spread_operators.js&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-javascript hljs&amp;quot; data-lang=&amp;quot;javascript&amp;quot;&amp;gt;/**
 * Opérateur de rest:
 * const add = (...operandes) =&amp;amp;gt; a + b;
 * ou avec parametres avec valeur par défaut
 * const add = (a=0, b=0, ...operandes) =&amp;amp;gt; a + b;
 */

/**
 * spread opérateur:
 * récupère l&amp;#39;ensemble des elements d&amp;#39;une collection,
 * dans un array
 */
const user_ages = [25, 56, 12, 58, 41, 62, 26];

const max_user_age = Math.max(...user_ages);
const min_user_age = Math.min(...user_ages);

console.assert(max_user_age == 62);
console.assert(min_user_age == 12);

console.log(&amp;quot;---------&amp;quot;);&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;#toc_js&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;underline&amp;quot;&amp;gt;Intro Javascript&amp;lt;/span&amp;gt;&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;destructuring&amp;quot;&amp;gt;分割代入&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;09_destructuring.js&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-javascript hljs&amp;quot; data-lang=&amp;quot;javascript&amp;quot;&amp;gt;/**
 * L&amp;#39;affectation par décomposition (destructuring)
 */

const user = {
    first_name: &amp;quot;Oliv&amp;quot;,
    last_name: &amp;quot;Cher&amp;quot;,
    nick_name: &amp;quot;cheroliv&amp;quot;,
    gender: &amp;quot;male&amp;quot;,
    is_adult: true
};
console.log(user);

//première façon d&amp;#39;initaliser des variables sans destructuration
let first_name_legacy = user.first_name;
let last_name_legacy = user.last_name;
let nick_name_legacy = user.nick_name;
let gender_legacy = user.gender;
let is_adult_legacy = user.is_adult;

console.assert(&amp;quot;Oliv&amp;quot; === first_name_legacy);
console.assert(&amp;quot;Cher&amp;quot; === last_name_legacy);
console.assert(&amp;quot;cheroliv&amp;quot; === nick_name_legacy);
console.assert(&amp;quot;male&amp;quot; === gender_legacy);
console.assert(true === is_adult_legacy);
console.log(&amp;quot;---------&amp;quot;);
/**
 * Initialisation par déstructuration
 */
const {
    first_name,
    last_name,
    nick_name,
    gender,
    is_adult
} = user;

console.assert(user.first_name === first_name);
console.assert(user.last_name === last_name);
console.assert(user.nick_name === nick_name);
console.assert(user.gender === gender);
console.assert(user.is_adult === is_adult);

/**
 * Intialisation par déstructuration des arrays
 */
//cible explicite
const [a1, a2] = [15, 25, 17, 81, 51, 46];
console.assert(a1 === 15);
console.assert(a2 === 25);

//cible avec position par rapport aux index par virgules
//je veux b3 à 46
const [b1, b2, , , , b3] = [15, 25, 17, 81, 51, 46];
console.assert(b1 === 15);
console.assert(b2 === 25);
console.assert(b3 === 46);

//déstructuration avec operateur de rest
// je contruit un autre avec avec les elements
// à partir du premier élèment non destructuré
const [c1, c2, ...sub_arr] = [15, 25, 17, 81, 51, 46];
console.assert(b1 === 15);
console.assert(b2 === 25);
console.assert(sub_arr.length === 4);
console.assert(sub_arr[0] === 17);
console.assert(sub_arr[1] === 81);
console.assert(sub_arr[2] === 51);
console.assert(sub_arr[3] === 46);


// Une boucle pour comparer le resultat attendu
for (const [i, value] of[15, 25, 17, 81, 51, 46].entries()) {
    //on reconstruit le tableau à chaque iteration
    console.assert([c1, c2].concat(sub_arr)[i] === value);
}&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;#toc_js&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;underline&amp;quot;&amp;gt;Intro Javascript&amp;lt;/span&amp;gt;&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;import_export&amp;quot;&amp;gt;モジュールのインポートとエクスポート&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;10_module_import_export.js&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-javascript hljs&amp;quot; data-lang=&amp;quot;javascript&amp;quot;&amp;gt;/**
 * Import et export de module
 *
 * Dans le fichier html
 * au niveau de la balise d&amp;#39;import de script
 * spécifier le type module
 *
 * 1er technique: import nommé des fonctions:
 * import { sum, minus, times, div, rem } from &amp;quot;./dummy_math_functions.js&amp;quot;;
 *
 * 2eme technique: import global des fonction avec l&amp;#39;asterisque(*)
 * en préfixant l&amp;#39;import par un nommage du fichier importé:
 * import * as math from &amp;quot;./dummy_math_functions.js&amp;quot;;
 *
 * 3eme technique: import par alias avec le mot clé &amp;quot;as&amp;quot;
 * import {
 *     sum as add,
 *     minus as substract,
 *     times as multiply,
 *     div as divide,
 *     rem as modulo
 * } from &amp;quot;./dummy_math_functions.js&amp;quot;;
 */

import {
    sum,
    minus,
    times,
    div,
    rem
} from &amp;quot;./dummy_math_functions.js&amp;quot;;

console.assert(sum(1, 1) === 2);
console.assert(minus(4, 2) === 2);
console.assert(times(2, 2) === 4);
console.assert(div(4, 2) === 2);
console.assert(rem(4, 2) === 0);&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;dummy_math_functions.js&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-javascript hljs&amp;quot; data-lang=&amp;quot;javascript&amp;quot;&amp;gt;//sum
const sum = (x, y) =&amp;amp;gt; x + y;

// subtraction
const minus = (x, y) =&amp;amp;gt; x - y;

// multiplication
const times = (x, y) =&amp;amp;gt; x * y;

// division
const div = (x, y) =&amp;amp;gt; x / y;

// remainder: reste de la division euclidiene
const rem = (x, y) =&amp;amp;gt; x % y;

// log sum
const sum_log = (x, y) =&amp;amp;gt; console.log(sum(x, y));

// log subtraction
const minus_log = (x, y) =&amp;amp;gt; console.log(minus(x, y));

// log multiplication
const times_log = (x, y) =&amp;amp;gt; console.log(times(x, y));

// log division
const div_log = (x, y) =&amp;amp;gt; console.log(div(x, y));

// log remainder
const rem_log = (x, y) =&amp;amp;gt; console.log(rem(x, y));

export {
    sum,
    minus,
    times,
    div,
    rem,
    sum_log,
    minus_log,
    times_log,
    div_log,
    rem_log
};&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;#toc_js&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;underline&amp;quot;&amp;gt;Intro Javascript&amp;lt;/span&amp;gt;&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;classes&amp;quot;&amp;gt;クラスの使用&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;11_classes.js&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-javascript hljs&amp;quot; data-lang=&amp;quot;javascript&amp;quot;&amp;gt;/**
 * Utilisation des classes
 */
//creation d&amp;#39;un objet
class Account {
    constructor(username) {
        this.username = username;
    }
};

const acc1 = new Account(&amp;quot;cheroliv&amp;quot;);
console.table(acc1);
console.assert(acc1.username === &amp;quot;cheroliv&amp;quot;);

console.log(&amp;quot;---------&amp;quot;);

//création d&amp;#39;un objet et ajout de getter et setter(accesseurs)
class AccountInfo {
    constructor(username) {
        this._username = username;
    }

    get username() {
        return this._username;
    }

    /**
     * @param {(arg0: string) =&amp;amp;gt; void} new_username
     */
    set new_username(new_username) {
        this._username = new_username;
    }
};

const acc_info1 = new AccountInfo(&amp;quot;cheroliv&amp;quot;);
console.table(acc_info1);
//accés au membre _username avec le getter username()
console.assert(acc_info1.username === &amp;quot;cheroliv&amp;quot;);

//update la valeur username de acc_info1 avec le setter
acc_info1.new_username = &amp;quot;imrandeh&amp;quot;;
console.assert(acc_info1.username === &amp;quot;imrandeh&amp;quot;);

console.log(&amp;quot;---------&amp;quot;);&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;#toc_js&amp;quot;&amp;gt;&amp;lt;span class=&amp;quot;underline&amp;quot;&amp;gt;Intro Javascript&amp;lt;/span&amp;gt;&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;</description>
        </item><item>
            <title>メモ フレーミング</title>
            <link >https://cheroliv.com/blog/2022/0054_memo_cadrage_post.html</link>
            <pubDate>Sat, 31 Dec 2022 00:00:00 +0000</pubDate>
            <guid isPermaLink="false">blog/2022/0054_memo_cadrage_post.html</guid>
            <description>&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_フレーミング&amp;quot;&amp;gt;フレーミング&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_アトリエ_1_ビジョン&amp;quot;&amp;gt;アトリエ 1 : ビジョン&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;sect3&amp;quot;&amp;gt;
&amp;lt;h4 id=&amp;quot;_パターンqqoqcp_誰何どこいつどのようになぜ&amp;quot;&amp;gt;パターン「QQOQCP」 – 誰、何、どこ、いつ、どのように、なぜ&amp;lt;/h4&amp;gt;

&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect3&amp;quot;&amp;gt;
&amp;lt;h4 id=&amp;quot;_2_product_vision_board&amp;quot;&amp;gt;2. Product Vision Board&amp;lt;/h4&amp;gt;
&amp;lt;div class=&amp;quot;sect4&amp;quot;&amp;gt;
&amp;lt;h5 id=&amp;quot;_対象グループ&amp;quot;&amp;gt;対象グループ&amp;lt;/h5&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;製品またはオファーを使用しているユーザーは誰ですか？ （直接、間接）&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect4&amp;quot;&amp;gt;
&amp;lt;h5 id=&amp;quot;_必要&amp;quot;&amp;gt;必要&amp;lt;/h5&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;アプリケーションのキーユーザーの5つの主要なニーズとは何ですか？&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect4&amp;quot;&amp;gt;
&amp;lt;h5 id=&amp;quot;_製品&amp;quot;&amp;gt;製品&amp;lt;/h5&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;私の価値提案は何ですか？ 製品の主要な5つの機能で、何に応えることができるのは 必要&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect4&amp;quot;&amp;gt;
&amp;lt;h5 id=&amp;quot;_ビジネスゴール&amp;quot;&amp;gt;ビジネスゴール&amp;lt;/h5&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;成功の基準は何ですか？&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect4&amp;quot;&amp;gt;
&amp;lt;h5 id=&amp;quot;_ビジョン&amp;quot;&amp;gt;ビジョン&amp;lt;/h5&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;4つの列が完成したら、Product Visionのビジョン部分を入力する必要があります。 Boardを一文で表す。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_ワークショップ_2_ペルソナユーザージャーニー&amp;quot;&amp;gt;ワークショップ 2: ペルソナ/ユーザージャーニー&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;各ペルソナに対してユーザージャーニーを定義する:&amp;lt;/div&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;誰が私のサービスを利用しますか？（対象）&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;彼は何をしたいですか？(しかし)&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;彼はどうやってやるつもりですか？ (ユーザージャーニー)&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_ワークショップ_3_ゾーニング_ストーリーボード_サイトマップ&amp;quot;&amp;gt;ワークショップ 3: ゾーニング, ストーリーボード, サイトマップ&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;sect3&amp;quot;&amp;gt;
&amp;lt;h4 id=&amp;quot;_1_ゾーニング&amp;quot;&amp;gt;1. ゾーニング&amp;lt;/h4&amp;gt;

&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect3&amp;quot;&amp;gt;
&amp;lt;h4 id=&amp;quot;_2_ストーリーボード&amp;quot;&amp;gt;2. ストーリーボード&amp;lt;/h4&amp;gt;

&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect3&amp;quot;&amp;gt;
&amp;lt;h4 id=&amp;quot;_3_サイトマップ&amp;quot;&amp;gt;3. サイトマップ&amp;lt;/h4&amp;gt;

&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_ワークショップ4_ワイヤーフレームムードボード&amp;quot;&amp;gt;ワークショップ4: ワイヤーフレーム/ムードボード&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;sect3&amp;quot;&amp;gt;
&amp;lt;h4 id=&amp;quot;_1_ワイヤーフレーム&amp;quot;&amp;gt;1. ワイヤーフレーム&amp;lt;/h4&amp;gt;

&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect3&amp;quot;&amp;gt;
&amp;lt;h4 id=&amp;quot;_2_ムードボード&amp;quot;&amp;gt;2. ムードボード&amp;lt;/h4&amp;gt;

&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_ワークショップ5_ストーリー_マッピング_ユーザーストーリー&amp;quot;&amp;gt;ワークショップ5: ストーリー マッピング/ ユーザーストーリー&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;sect3&amp;quot;&amp;gt;
&amp;lt;h4 id=&amp;quot;_ストーリーマッピングusの優先順位&amp;quot;&amp;gt;ストーリーマッピング(USの優先順位)&amp;lt;/h4&amp;gt;

&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect3&amp;quot;&amp;gt;
&amp;lt;h4 id=&amp;quot;_type_dutilisateurとしてobjective_が欲しいreason_ために&amp;quot;&amp;gt;&amp;amp;lt;type d&amp;amp;#8217;utilisateur&amp;amp;gt;として、&amp;amp;lt;objective&amp;amp;gt; が欲しい。&amp;amp;lt;reason&amp;amp;gt; ために。&amp;lt;/h4&amp;gt;

&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_ワークショップ_6_バックログ&amp;quot;&amp;gt;ワークショップ 6: バックログ&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;https://www.atlassian.com/fr/agile/scrum/backlogs&amp;quot;&amp;gt;バックログ&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_アトリエ_7_テクニックと建築&amp;quot;&amp;gt;アトリエ 7: テクニックと建築&amp;lt;/h3&amp;gt;

&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;</description>
        </item><item>
            <title>Kotlinメモ</title>
            <link >https://cheroliv.com/blog/2022/0053_memo_kotlin_post.html</link>
            <pubDate>Sun, 29 May 2022 00:00:00 +0000</pubDate>
            <guid isPermaLink="false">blog/2022/0053_memo_kotlin_post.html</guid>
            <description>&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_良いリンク&amp;quot;&amp;gt;良いリンク&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;https://play.kotlinlang.org/&amp;quot;&amp;gt;kotlinlang プレイグラウンド&amp;lt;/a&amp;gt;+&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;https://arrow-kt.io/&amp;quot;&amp;gt;arrow.kt&amp;lt;/a&amp;gt;+&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;https://arkivanov.github.io/MVIKotlin/&amp;quot;&amp;gt;MVI:モデル ビュー インテント&amp;lt;/a&amp;gt;+&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;https://github.com/arkivanov/Essenty&amp;quot;&amp;gt;エッセンティ&amp;lt;/a&amp;gt;+&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;https://arkivanov.github.io/Decompose/&amp;quot;&amp;gt;分解&amp;lt;/a&amp;gt;(Note: Since no French text was provided to translate, there is no output.)&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_さまざまなコードスニペット&amp;quot;&amp;gt;さまざまなコードスニペット&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_マップリデュース&amp;quot;&amp;gt;マップリデュース&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;ビットのリストを文字列のリストに変換し、文字列のリストを要約する&amp;lt;br&amp;gt;
文字列の中で、連結を含む。 リクエスト (requestBodyContent:byte[]) が送信されたときにログを取る方法&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-kotlin hljs&amp;quot; data-lang=&amp;quot;kotlin&amp;quot;&amp;gt;log.info(
    requestBodyContent!!.map { it.toInt().toChar().toString() }
        .reduce { request: String, s: String -&amp;amp;gt; request + s }
)&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_enum_と_sealed_クラス&amp;quot;&amp;gt;enum と sealed クラス&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;投�稿：&amp;lt;a href=&amp;quot;0038_training_kotlin_enum_sealed_class_post&amp;quot; target=&amp;quot;&amp;quot;_blank&amp;quot;&amp;gt;kotlin の enum と sealed クラスのトレーニング&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_機能的インターフェイスとメソッド参照&amp;quot;&amp;gt;機能的インターフェイスとメソッド参照&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;エンティティをDTOのドメインモデルに変換することができ、参照メソッド(関数型スタイル-Java 8)を使います&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-kotlin hljs&amp;quot; data-lang=&amp;quot;kotlin&amp;quot;&amp;gt;fun findAllByLoginNot(
        pageable:Pageable,
        login:String)
    :Page&amp;amp;lt;UserDto&amp;amp;gt; {
    return userDao.findAllByLoginNot(
                    pageable,
                    login).map(::fromEntity)
}&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;一つのhttps://stackoverflow.com/a/22245383/837404[良い説明]&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_標準出力をキャプチャする&amp;quot;&amp;gt;標準出力をキャプチャする&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-kotlin hljs&amp;quot; data-lang=&amp;quot;kotlin&amp;quot;&amp;gt;package functional

import java.io.ByteArrayOutputStream
import java.io.PrintStream
import java.lang.System.out
import java.lang.System.setOut
import kotlin.test.AfterTest
import kotlin.test.BeforeTest
import kotlin.test.Test
import kotlin.test.assertEquals


class BasicsHOF {
    private val standardOut: PrintStream? = out
    private val outputStreamCaptor = ByteArrayOutputStream()

    @BeforeTest
    fun setUp() = setOut(PrintStream(outputStreamCaptor))

    @AfterTest
    fun tearDown() = setOut(standardOut)

    @Test
    fun `three times dope`() {

        3.times { println(&amp;quot;Hello&amp;quot;) }

        assertEquals(
            buildString {
                repeat(3) { append(&amp;quot;Hello\n&amp;quot;) }
                deleteAt(length - 1)
            }, outputStreamCaptor
                .toString()
                .trim()
        )
    }

    fun Int.times(fn: () -&amp;amp;gt; Unit) = (1..this).forEach { _ -&amp;amp;gt; fn() }
}&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_kotlinにおけるapplyrunletalsousewithの違いは何ですか&amp;quot;&amp;gt;Kotlinにおけるapply、run、let、also、use、withの違いは何ですか？&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;Kotlin 関数の比較とラムダ形式の利用 リファレンス&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_適用する&amp;quot;&amp;gt;適用する&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;導入 コトリンの関数`apply`, &amp;lt;code&amp;gt;run&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;let&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;also&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;use&amp;lt;/code&amp;gt;, et `with`様々な方法でオブジェクトを扱う手段を提供しています。それぞれに固有の使用例と挙動があります。さらに、ラムダ参照形式は既存のラムダ関数を参照することにより、コードをより読みやすく再利用しやすくします。&amp;lt;/div&amp;gt;
&amp;lt;p&amp;gt;機能`apply`これはオブジェクトの生成中に設定するために使用されます。呼び出されたオブジェクトを返します。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;ラムダ参照の例：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-kotlin hljs&amp;quot; data-lang=&amp;quot;kotlin&amp;quot;&amp;gt;val someObject = SomeClass().apply(::configureObject)&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;ラムダを使用した例：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-kotlin hljs&amp;quot; data-lang=&amp;quot;kotlin&amp;quot;&amp;gt;val someObject = SomeClass().apply {
// configuration des propriétés de someObject
}&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_実行&amp;quot;&amp;gt;実行&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;機能`run`オブジェクトに対してコードブロックを実行し、その結果を返すために使用されます。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;ラムダ参照の例：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-kotlin hljs&amp;quot; data-lang=&amp;quot;kotlin&amp;quot;&amp;gt;val result = someObject.run(::someFunction)&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;ラムダを使った例：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-kotlin hljs&amp;quot; data-lang=&amp;quot;kotlin&amp;quot;&amp;gt;val result = someObject.run {
// bloc de code à exécuter sur someObject
// la dernière expression est renvoyée
}&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_let&amp;quot;&amp;gt;let&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;機能`let`は、オブジェクト上でコードブロックを実行し、その結果を返すために使用されます。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;ラムダ参照の例：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-kotlin hljs&amp;quot; data-lang=&amp;quot;kotlin&amp;quot;&amp;gt;val result = someObject.let(::processObject)&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;ラムダを使った例：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-kotlin hljs&amp;quot; data-lang=&amp;quot;kotlin&amp;quot;&amp;gt;val result = someObject.let {
// bloc de code à exécuter sur someObject
// la dernière expression est renvoyée
}&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_また&amp;quot;&amp;gt;また&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;機能`also`これは、オブジェクトに追加のアクションを実行するために使用され、呼び出されたオブジェクトを返します。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;lambda 参照の例&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-kotlin hljs&amp;quot; data-lang=&amp;quot;kotlin&amp;quot;&amp;gt;someObject.also(::performAdditionalAction)&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;ラムダを使った例 :&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-kotlin hljs&amp;quot; data-lang=&amp;quot;kotlin&amp;quot;&amp;gt;someObject.also {
// action additionnelle sur someObject
}&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_think&amp;quot;&amp;gt;&amp;amp;lt;/think&amp;amp;gt;&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;機能`use`使用後に閉じる必要があるリソースを扱うために使用されます。自動的に関数を呼び出します。`close`ブロックの終わりに。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;ラムダ参照の例 :&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-kotlin hljs&amp;quot; data-lang=&amp;quot;kotlin&amp;quot;&amp;gt;someResource.use(::useResource)&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;lambda との例 :&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-kotlin hljs&amp;quot; data-lang=&amp;quot;kotlin&amp;quot;&amp;gt;someResource.use {
// travailler avec la ressource
}&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_with&amp;quot;&amp;gt;with&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;関数`with`オブジェクトの複数のメソッドを名前を繰り返さずに呼び出すために使用され、最後の式の結果を返します。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;例題とlambda参照 :&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-kotlin hljs&amp;quot; data-lang=&amp;quot;kotlin&amp;quot;&amp;gt;val result = with(someObject, ::processWithObject)&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;ラムダの例：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-kotlin hljs&amp;quot; data-lang=&amp;quot;kotlin&amp;quot;&amp;gt;val result = with(someObject) {
// appeler des méthodes sur someObject
// la dernière expression est renvoyée
}&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;ラムダ参照フォームまたはブロックを使用して`{}`ロジックを別々の関数にカプセル化することで、コードの可読性と再利用性が向上します&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_kotlinにおけるlet関数&amp;quot;&amp;gt;Kotlinにおけるlet関数 ＝＝&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;let は、副作用が適用されたオブジェクトを返しますか、それとも入力時の初期状態のオブジェクトを返しますか？（let によって異なります）&amp;lt;/div&amp;gt;
&amp;lt;p&amp;gt;関数`let`Kotlin は、オブジェクトに対して操作を行い、異なる結果を返すために使用されます。ただし、関数については重要な点に注意する必要があります。`let`呼び出されたオブジェクトの初期状態を変更しません。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;table class=&amp;quot;tableblock frame-all grid-all stretch&amp;quot;&amp;gt;
&amp;lt;colgroup&amp;gt;
&amp;lt;col style=&amp;quot;width: 50%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 50%;&amp;quot;&amp;gt;
&amp;lt;/colgroup&amp;gt;
&amp;lt;tbody&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;署名&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;code&amp;gt;inline fun &amp;amp;lt;T, R&amp;amp;gt; T.let(block: (T) &amp;amp;#8594; R): R&amp;lt;/code&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/tbody&amp;gt;
&amp;lt;/table&amp;gt;
&amp;lt;table class=&amp;quot;tableblock frame-all grid-all stretch&amp;quot;&amp;gt;
&amp;lt;colgroup&amp;gt;
&amp;lt;col style=&amp;quot;width: 50%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 50%;&amp;quot;&amp;gt;
&amp;lt;/colgroup&amp;gt;
&amp;lt;tbody&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;使用法&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;機能`let`は、オブジェクトに変換を適用し、これらの変換に基づいた結果を得るために一般的に使用されます。&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/tbody&amp;gt;
&amp;lt;/table&amp;gt;
&amp;lt;table class=&amp;quot;tableblock frame-all grid-all stretch&amp;quot;&amp;gt;
&amp;lt;colgroup&amp;gt;
&amp;lt;col style=&amp;quot;width: 50%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 50%;&amp;quot;&amp;gt;
&amp;lt;/colgroup&amp;gt;
&amp;lt;tbody&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;結果&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;関数が返す値`let`は引数として渡されたラムダ式の結果であり、通常はオブジェクトに対して行われた操作の結果です。&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/tbody&amp;gt;
&amp;lt;/table&amp;gt;
&amp;lt;table class=&amp;quot;tableblock frame-all grid-all stretch&amp;quot;&amp;gt;
&amp;lt;colgroup&amp;gt;
&amp;lt;col style=&amp;quot;width: 50%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 50%;&amp;quot;&amp;gt;
&amp;lt;/colgroup&amp;gt;
&amp;lt;tbody&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;境界効果&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;関数であるにもかかわらず`let`ラムダ式で使用されるときにオブジェクトに副作用を及ぼす可能性はあるが、オブジェクト自身の初期状態を変更するわけではない。&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/tbody&amp;gt;
&amp;lt;/table&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;したがって、関数`let`これは、オブジェクトに対して操作を行いながら導出結果を得つつ、元のオブジェクトの整合性を保つエレガントな方法です。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;</description>
        </item><item>
            <title>JVMメモ</title>
            <link >https://cheroliv.com/blog/2022/0052_memo_jvm_post.html</link>
            <pubDate>Sat, 28 May 2022 00:00:00 +0000</pubDate>
            <guid isPermaLink="false">blog/2022/0052_memo_jvm_post.html</guid>
            <description>&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;toc&amp;quot;&amp;gt;目次&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;olist arabic&amp;quot;&amp;gt;
&amp;lt;ol class=&amp;quot;arabic&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;#char&amp;quot;&amp;gt;文字列と文字&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;#math&amp;quot;&amp;gt;数と数学&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;#date&amp;quot;&amp;gt;日付と時刻&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;#java8date&amp;quot;&amp;gt;日付と時刻 java8&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;#arrCol&amp;quot;&amp;gt;配列とコレクション&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;#sysProp&amp;quot;&amp;gt;System.Properties&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;#threads&amp;quot;&amp;gt;スレッド&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;#regex&amp;quot;&amp;gt;正規表現&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ol&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;char&amp;quot;&amp;gt;文字列と文字&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-kotlin hljs&amp;quot; data-lang=&amp;quot;kotlin&amp;quot;&amp;gt;import java.text.Collator
import java.util.*
import kotlin.test.*

class StringsTest {
    @Test
    fun `chaines de caractères et caractères`() {
        //inférence de type
        val s = &amp;quot;C&amp;#39;est&amp;quot;
        assertEquals(&amp;quot;C&amp;#39;est&amp;quot;, s)

        //concaténation
        val t: String = s + &amp;quot; le moment.&amp;quot;
        assertEquals(&amp;quot;C&amp;#39;est le moment.&amp;quot;, t)

        // StringBuilder
        val t1: String = s + buildString { append(&amp;quot; le moment.&amp;quot;) }
        assertEquals(&amp;quot;C&amp;#39;est le moment.&amp;quot;, t1)

        //interpolation
        val t2 = &amp;quot;$s le moment.&amp;quot;
        assertEquals(&amp;quot;C&amp;#39;est le moment.&amp;quot;, t2)

        //multiligne chaine de caractères
        val t3 = &amp;quot;&amp;quot;&amp;quot;$s le moment.&amp;quot;&amp;quot;&amp;quot;
        assertEquals(&amp;quot;C&amp;#39;est le moment.&amp;quot;, t3)

        //conversion de type
        val t4 = t + &amp;quot; &amp;quot; + 23.4
        assertEquals(&amp;quot;C&amp;#39;est le moment. 23.4&amp;quot;, t4)

        val t5 = &amp;#39;C&amp;#39;.toString()
        assertEquals(&amp;quot;C&amp;quot;, t5)

        //taille de la chaine de caractères
        assertEquals(16, t.length)

        //sous-chaine d&amp;#39;une chaine de caractères

        //retourne une chaine de caractères contenant,
        //les caractères aux positions x à y-1
        //sub = t.substring(x, y)

        //t = &amp;quot;C&amp;#39;est le moment.&amp;quot;
        //retourne les caractères 6 et 7
        var sub = t.substring(6, 8)
        assertEquals(&amp;quot;le&amp;quot;, sub)

        //retourne les caractères 0 à 4
        sub = t.substring(0, 5)
        assertEquals(&amp;quot;C&amp;#39;est&amp;quot;, sub)

        //la longueur d&amp;#39;une sous-chaine est toujours égale (y-x)
        val numChars = sub.length
        assertEquals(5 - 0, numChars)

        //extraction des caractères d&amp;#39;une chaine
        assertEquals(&amp;#39;e&amp;#39;, t.elementAt(2))
        assertEquals(&amp;#39;e&amp;#39;, t.get(2))
        assertEquals(&amp;#39;e&amp;#39;, t[2])

        //conversion d&amp;#39;une chaine en tableau de caractères
        val ca = t.toCharArray()
        assertEquals(t.length, ca.size)
        t.mapIndexed { index, char -&amp;amp;gt; assertEquals(char, ca[index]) }

        //place les 4 premiers caractères de t1
        //dans le tableau ca a la position 2
        (t as java.lang.String).getChars(
            /* srcBegin = */ 0,
            /* srcEnd = */ 3,
            /* dst = */ ca,
            /* dstBegin = */ 1
        )
        assertEquals(&amp;quot;CC&amp;#39;et le moment.&amp;quot;, String(ca))
        //colle tous les caractères dans un meme string
        assertEquals(&amp;quot;CC&amp;#39;et le moment.&amp;quot;, ca.concatToString())

        //to lower case
        assertEquals(&amp;quot;c&amp;#39;est le moment.&amp;quot;, t.toLowerCase())
        assertEquals(&amp;quot;c&amp;#39;est le moment.&amp;quot;, t.lowercase())

        //to upper case
        assertEquals(&amp;quot;C&amp;#39;EST LE MOMENT.&amp;quot;, t.toUpperCase())
        assertEquals(&amp;quot;C&amp;#39;EST LE MOMENT.&amp;quot;, t.uppercase())

        //comparaison de chaines de caractères
        //t = &amp;quot;C&amp;#39;est le moment.&amp;quot;
        assertFalse(t.equals(&amp;quot;hello&amp;quot;))
        assertFalse(t == &amp;quot;hello&amp;quot;)

        //ignore la casse
        assertTrue(t.equalsIgnoreCase(&amp;quot;C&amp;#39;EST LE MOMENT.&amp;quot;))
        assertTrue(t.equals(&amp;quot;C&amp;#39;EST LE MOMENT.&amp;quot;, ignoreCase = true))

        //démarre par
        assertTrue(t.startsWith(&amp;quot;C&amp;#39;est&amp;quot;))
        //se finit par
        assertTrue(t.endsWith(&amp;quot;le moment.&amp;quot;))

        //compareTo
        //retourne une valeur &amp;amp;lt; 0, car s est
        //alphabétiquement avant &amp;quot;N&amp;#39;est&amp;quot;
        val r1: Int = s.compareTo(&amp;quot;N&amp;#39;est&amp;quot;)
        assertTrue(r1 &amp;amp;lt; 0)

        //variante ignorant la casse
        val r1Prime: Int = (s as java.lang.String).compareToIgnoreCase(&amp;quot;n&amp;#39;est&amp;quot;)
        assertTrue(r1Prime &amp;amp;lt; 0)

        //retourne 0 si les chaines sont equivalente
        val r2: Int = s.compareTo(&amp;quot;C&amp;#39;est&amp;quot;)
        assertEquals(0, r2)

        //retourne une valeur &amp;amp;gt; 0 car s vient apres &amp;quot;B&amp;#39;est&amp;quot;
        val r3: Int = s.compareTo(&amp;quot;B&amp;#39;est&amp;quot;)
        assertTrue(r3 &amp;amp;gt; 0)

        //Recherche de caractères et de sous-chaines de caractères

        //recherche de caractères
        //position du premier caractères &amp;#39;t&amp;#39;
        var pos = t.indexOf(&amp;#39;t&amp;#39;)
        assertEquals(4, pos)

        //position du suivant
        pos = t.indexOf(&amp;#39;t&amp;#39;, pos + 1)
        assertEquals(14, pos)

        //retour d&amp;#39;érreur -1 si absence de suivant
        pos = t.indexOf(&amp;#39;t&amp;#39;, pos + 1)
        assertEquals(-1, pos)

        //position du dernier &amp;#39;t&amp;#39; dans la chaine: 14
        pos = t.lastIndexOf(&amp;#39;t&amp;#39;)
        assertEquals(14, pos)

        //recherche de &amp;#39;t&amp;#39; vers l&amp;#39;arrière a partir du caractères 13
        pos = t.lastIndexOf(&amp;#39;t&amp;#39;, pos - 1)
        assertEquals(4, pos)

        //recherche de sous-chaines
        //retourne 2
        pos = t.indexOf(&amp;quot;est&amp;quot;)
        assertEquals(2, pos)

        //&amp;quot;est&amp;quot; n&amp;#39;apparait qu&amp;#39;une seule fois: retourne -1
        pos = t.indexOf(&amp;quot;est&amp;quot;, pos + 1)
        assertEquals(-1, pos)

        //recherche d&amp;#39;une sous-chaine depuis l&amp;#39;arrière
        //t = &amp;quot;C&amp;#39;est le moment.&amp;quot;
        //retourne 6
        pos = t.lastIndexOf(&amp;quot;le &amp;quot;)
        assertEquals(6, pos)

        //extrait depuis la position 9,
        //renvoi toute la chaine après &amp;quot;le &amp;quot;
        val noun = t.substring(pos + 3)
        assertEquals(-1, noun.indexOf(&amp;quot;le &amp;quot;))

        //remplacement de toutes les instances d&amp;#39;un caractère
        //par un autre caractère
        //ne fonctionne que avec les caractères, pas les chaines
        val exclaim: String = t.replace(&amp;#39;.&amp;#39;, &amp;#39;!&amp;#39;)
        assertEquals(&amp;#39;!&amp;#39;, exclaim.get(exclaim.length - 1))
        assertEquals(exclaim.length - 1, exclaim.indexOf(&amp;#39;!&amp;#39;))
        assertEquals(-1, exclaim.indexOf(&amp;#39;.&amp;#39;))

        //suppression des espaces blancs
        //au début et à la fin d&amp;#39;une chaine
        val noextraspaces = t.trim()
        assertNotEquals(&amp;#39; &amp;#39;, noextraspaces.get(0))
        assertNotEquals(&amp;#39; &amp;#39;, noextraspaces.get(noextraspaces.length - 1))

        //extraction des instances uniques de chaines de caractères
        //avec intern()
        val s1 = s.intern()
        assertEquals(s, s1)
        val s2 = &amp;quot;C&amp;#39;est&amp;quot;.intern()
        assertEquals(&amp;quot;C&amp;#39;est&amp;quot;, s2)
        assertEquals(s1, s2)

        //StringBuilder pour manipuler les caractères d&amp;#39;une chaine de caractères
        //crée un tampon StringBuilder à partir d&amp;#39;une chaine de caractères
        val b = StringBuilder(&amp;quot;N&amp;#39;est&amp;quot;)

        //extrait et définit des caractères individuel du tampon StringBuilder
        //le caractères à l&amp;#39;index 0
        val c: Char = b.get(0)
        assertEquals(&amp;#39;N&amp;#39;, c)

        //modifier le premier caractère de la chaine
        b.setCharAt(0, &amp;#39;C&amp;#39;)
        assertEquals(s, b.toString())

        //ajouter des données à un StringBuilder
        b.append(&amp;#39; &amp;#39;)
        b.append(&amp;quot;le moment.&amp;quot;)
        b.append(23)

        //insère des chaines de caractères ou autre dans le StringBuilder
        b.insert(6, &amp;quot;pas &amp;quot;)
        assertEquals(&amp;quot;C&amp;#39;est pas le moment.23&amp;quot;, b.toString())

        //remplace un sous ensemble de caractères
        //avec une chaine de caractères donnée
        b.replace(2, 9, &amp;quot;est&amp;quot;)
        assertEquals(&amp;quot;C&amp;#39;est le moment.23&amp;quot;, b.toString())

        //supprime les caractères
        b.delete(15, 18)
        assertEquals(&amp;quot;C&amp;#39;est le moment&amp;quot;, b.toString())
        b.deleteCharAt(2)
        assertEquals(&amp;quot;C&amp;#39;st le moment&amp;quot;, b.toString())

        //insert à la postion 2 et décale reste à droite(sans perte de données)
        b.insert(2, &amp;#39;e&amp;#39;)

        //tronque la taille de la donnée
        b.setLength(5)
        assertEquals(&amp;quot;C&amp;#39;est&amp;quot;, b.toString())

        //inverse les caractères de la chaine
        b.reverse()
        assertEquals(&amp;quot;tse&amp;#39;C&amp;quot;, b.toString())

        //écrase le StringBuilder, pret à etre réutilisé
        b.setLength(0)
        assertEquals(&amp;quot;&amp;quot;, b.toString())

        //java.util.StringTokenizer pour fragmenter une chaine
        //de caractères en un ensemble de mots
        var st = StringTokenizer(t)
        //nb d&amp;#39;items encore présentent dans la file
        assertEquals(3, st.countTokens())

        //est ce que il y a encore des items dans la file
        assertTrue(st.hasMoreTokens())

        //récupérer le token courrant
        assertEquals(&amp;quot;C&amp;#39;est&amp;quot;, st.nextToken())
        assertEquals(&amp;quot;le&amp;quot;, st.nextToken())
        assertEquals(&amp;quot;moment.&amp;quot;, st.nextToken())
        assertFalse(st.hasMoreTokens())
        assertEquals(0, st.countTokens())

        //extraire des occurences de mots délimités
        //par des caractères autres que des expaces.
        val str = &amp;quot;a:b:c:d&amp;quot;
        st = StringTokenizer(str, &amp;quot;:&amp;quot;)
        assertEquals(4, st.countTokens())
        assertTrue(st.hasMoreTokens())
        assertEquals(&amp;quot;a&amp;quot;, st.nextToken())
        assertEquals(&amp;quot;b&amp;quot;, st.nextToken())
        assertEquals(&amp;quot;c&amp;quot;, st.nextToken())
        assertEquals(&amp;quot;d&amp;quot;, st.nextToken())
        assertFalse(st.hasMoreTokens())
        assertEquals(0, st.countTokens())


        //text=&amp;quot;C&amp;#39;est le moment.&amp;quot;
        val text = t.toCharArray()
        var p = 0

        //sauter les espaces de tete
        //pour ramener p à la position du premier caractère imprimable
        while ((p &amp;amp;lt; text.size) &amp;amp;amp;&amp;amp;amp;
            (Character.isWhitespace(text[p]))
        ) p++
        assertEquals(0, p)
        assertEquals(&amp;quot;C&amp;#39;est le moment.&amp;quot;, text.concatToString())

        //met le premier mot du texte en majuscule
        while (p &amp;amp;lt; text.size &amp;amp;amp;&amp;amp;amp; Character.isLetter(text[p])) {
            text[p] = Character.toUpperCase(text[p])
            p++
        }
        assertEquals(1, p)
        assertEquals(&amp;#39;C&amp;#39;, text[0])
        assertTrue(Character.isUpperCase(text[0]))
        assertFalse(Character.isLetter(text[1]))

        //comparer des chaines de caractères
        // avec les contrainte la locale système
        val col = Collator.getInstance()
        //le résulat est négatif car chica
        //est avant chico dans l&amp;#39;ordre alphabétique
        assertTrue(col.compare(&amp;quot;chica&amp;quot;, &amp;quot;chico&amp;quot;) &amp;amp;lt; 0)
    }
}&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;#toc&amp;quot;&amp;gt;目次&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;math&amp;quot;&amp;gt;数と数学&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-kotlin hljs&amp;quot; data-lang=&amp;quot;kotlin&amp;quot;&amp;gt;import java.math.BigInteger
import java.security.SecureRandom
import java.text.NumberFormat
import java.util.*
import kotlin.test.*

class NumbersMathTest {
    @Test
    fun `Nombres et Math`() {
        //Constantes utiles
        Byte.MIN_VALUE
        Byte.MAX_VALUE
        Short.MIN_VALUE
        Short.MAX_VALUE
        Float.MIN_VALUE
        Float.MAX_VALUE
        Math.PI
        Math.E
        val s = &amp;quot;-42&amp;quot;
        //conversion de chaine de caractères
        //vers un nombre, si possible.
        var b: Byte = java.lang.Byte.parseByte(s)
        var sh: Short = java.lang.Short.parseShort(s)
        var i: Int = java.lang.Integer.parseInt(s)
        var l: Long = java.lang.Long.parseLong(s)
        var f: Float = java.lang.Float.parseFloat(s)
        var d: Double = java.lang.Double.parseDouble(s)

        //valeur exacte
        val f_exac = java.lang.Float.valueOf(s)
        val d_exac = java.lang.Double.valueOf(s)

        //les routines de conversions entière gérent
        //les nombres dans diverses bases.
        //1011 en binare est égal a 11 en base dix
        b = java.lang.Byte.parseByte(&amp;quot;1011&amp;quot;, 2)
        assertEquals(11, b)
        //ff en base 16(hexa) est égal à 255 en base dix.
        sh = java.lang.Short.parseShort(&amp;quot;ff&amp;quot;, 16)
        assertEquals(255, sh)

        //la méthode valueOf() peut gérer des bases arbitraires.
        i = java.lang.Integer.valueOf(&amp;quot;egg&amp;quot;, 17).toInt()
        assertEquals(4334, i)

        //la méthode decode() gére les representations octale,
        //décimal, hexadécimal, en fonction du préfixe numérique
        //de la chaine de caractères
        //un 0 de tete signifie base 8
        //un 0x de tete signifie base 16
        //les autres sont en base 10
        val sho = java.lang.Short.decode(&amp;quot;0377&amp;quot;)

        //la classe Integer peut convertir les nombres
        //en diverses chaines de caractères.
        val decimal = java.lang.Integer.toString(42)
        assertEquals(&amp;quot;42&amp;quot;, decimal)

        val decimal_ = 42.toString()
        assertEquals(&amp;quot;42&amp;quot;, decimal_)

        val binary = java.lang.Integer.toBinaryString(42)
        assertEquals(&amp;quot;101010&amp;quot;, binary)

        val octal = java.lang.Integer.toOctalString(42)
        assertEquals(&amp;quot;52&amp;quot;, octal)

        val hex = java.lang.Integer.toHexString(42)
        assertEquals(&amp;quot;2a&amp;quot;, hex)

        val base36 = java.lang.Integer.toString(42, 36)
        assertEquals(&amp;quot;16&amp;quot;, base36)

        val base36_ = 42.toString(36)
        assertEquals(&amp;quot;16&amp;quot;, base36_)

        //java.text.NumberFormat effectue la conversion
        // d&amp;#39;une maniere spécifique aux parametres locaux
        //sans parametre prend la local systeme comme reference
        val nf = NumberFormat.getNumberInstance(Locale.FRANCE)
        val formatted_number = nf.format(9876543.21)
        assertNotEquals(&amp;quot;9876543.21&amp;quot;, formatted_number)

        //parse la chaine de caractères en fonction des parametres locaux(fr)
        val n = nf.parse(&amp;quot;1234567,89&amp;quot;)
        assertEquals(1234567.89, n)

        //les valeurs monétaires sont parfois formaté
        // d&amp;#39;une maniere differente des nombres
        val money_format = NumberFormat.getCurrencyInstance(Locale.FRANCE)
        assertEquals(&amp;quot;123,40 €&amp;quot;, money_format.format(1234.56))

        //java.lang.Math
        d = Math.toRadians(27.0)
        d = Math.cos(d)
        d = Math.sqrt(d)
        d = Math.log(d)
        d = Math.exp(d)
        d = Math.pow(10.0, d)
        d = Math.atan(d)
        d = Math.toDegrees(d)
        //arrondi au dessus
        val up = Math.ceil(d)
        //arrondi au dessous
        val down = Math.floor(d)
        //arrondi au plus près
        val nearest = Math.round(d)

        //java.lang.Math.Random()
        val r = Math.random()
        assertTrue(r &amp;amp;gt;= 0.0 &amp;amp;amp;&amp;amp;amp; r &amp;amp;lt; 1.0)

        //créé un nouvel objet Random, en l&amp;#39;initialisant
        //avec l&amp;#39;heure courante
        val generator = java.util.Random(System.currentTimeMillis())

        //prochaine valeur aléatoire de taille double
        d = generator.nextDouble()
        assertTrue((d &amp;amp;gt;= 0.0) &amp;amp;amp;&amp;amp;amp; (d &amp;amp;lt; 1.0))


        //prochaine valeur aléatoire de taille float
        f = generator.nextFloat()
        assertTrue((f &amp;amp;gt;= 0.0) &amp;amp;amp;&amp;amp;amp; (f &amp;amp;lt; 1.0))


        //prochaine valeur aléatoire de taille long
        l = generator.nextLong()
        assertTrue(
            (Math.abs(l) &amp;amp;lt;= Long.MAX_VALUE) &amp;amp;amp;&amp;amp;amp;
                    (Math.abs(l) &amp;amp;gt;= 0)
        )


        //prochaine valeur aléatoire de taille int
        i = generator.nextInt()
        assertTrue(
            (Math.abs(i) &amp;amp;lt;= java.lang.Integer.MAX_VALUE) &amp;amp;amp;&amp;amp;amp;
                    (Math.abs(i) &amp;amp;gt;= 0)
        )

        val limit = 100
        //prochaine valeur aléatoire de taille int
        //la limit max du ramdom est ramené à limit
        //et la limit min est 0
        i = generator.nextInt(limit)
        assertTrue(i in 0 until limit)


        //prochaine valeur aléatoire de taille booléen
        val bool = generator.nextBoolean()
        assertNotNull(bool)


        //valeur moyenne 0.0, déviation standard 1.0
        d = generator.nextGaussian()


        //randoms bytes
        //rempli un tableau avec des valeurs byte aléatoires
        val b_arr = ByteArray(128)
        generator.nextBytes(b_arr)
        b_arr.iterator().forEachRemaining {
            assertTrue(
                it &amp;amp;lt;= Byte.MAX_VALUE &amp;amp;amp;&amp;amp;amp;
                        it &amp;amp;gt;= Byte.MIN_VALUE
            )
        }

        //java.security.SecureRandom pour les nombres aléatoires
        //utilisé en cryptographie
        val secure_generator = SecureRandom()
        //le générateur génère sa propre tete de liste sur 16 octets
        secure_generator.setSeed(secure_generator.generateSeed(16))
        val sec_b_arr = ByteArray(128)
        secure_generator.nextBytes(sec_b_arr)
        sec_b_arr.iterator().forEachRemaining {
            assertTrue(
                it &amp;amp;lt;= java.lang.Byte.MAX_VALUE &amp;amp;amp;&amp;amp;amp;
                        it &amp;amp;gt;= java.lang.Byte.MIN_VALUE
            )
        }

        //java.math.BigDecimal java.math.BigInteger
        //pour travailler sur des grandes valeurs.
        //calcule de la factorielle de 1000
        var total = BigInteger.valueOf(1)
        (2..1000).forEach {
            total = total.multiply(BigInteger.valueOf(it.toLong()))
        }
        assertTrue(total.toString().length == 2568)
    }
}&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;#toc&amp;quot;&amp;gt;目次&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;date&amp;quot;&amp;gt;日付と時刻&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-kotlin hljs&amp;quot; data-lang=&amp;quot;kotlin&amp;quot;&amp;gt;import java.text.DateFormat
import java.text.SimpleDateFormat
import java.time.Instant
import java.util.*
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertTrue

class DatesHoursTest {
    @Test
    fun `Dates et heures`() {
        //l&amp;#39;heure courante en millisecondes
        val t0 = System.currentTimeMillis()
        //une autre représentation de la meme information
        val now = java.util.Date()
        //converti un objet java.util.Date en une valeur long.
        val t1 = now.getTime()
        assertTrue(t1 &amp;amp;gt; Instant.EPOCH.toEpochMilli())
        //kotlin property access syntaxe style
        val t1_prime = now.time

        //java.text.DateFormat
        //affiche la date d&amp;#39;aujourd&amp;#39;hui en utilisant le format
        //par défaut des parametres locaux
        val defaultDateFormat = DateFormat.getDateInstance()
        //personnalisation du formatage et de la locale
        val df = DateFormat.getDateInstance(DateFormat.LONG, Locale.FRANCE)
        val localeFormattedDate = df.format(Date())

        //constantes pour les styles de pattern de formatage
        assertEquals(0, DateFormat.FULL)
        assertEquals(1, DateFormat.LONG)
        assertEquals(2, DateFormat.MEDIUM)
        assertEquals(3, DateFormat.SHORT)
        assertEquals(2, DateFormat.DEFAULT)

        //utilise pour l&amp;#39;heure un format abrégé avec
        //des parametres personnalisés
        val tf = DateFormat.getTimeInstance(
            DateFormat.SHORT,
            Locale.FRANCE
        )
        //affiche l&amp;#39;heure en utilisant le format de tf
        val shortTime = tf.format(Date())
        assertTrue(shortTime.contains(&amp;#39;:&amp;#39;))

        //affiche la date et l&amp;#39;heure en utilisant
        //un format détaillé
        val longTimeStamp = DateFormat.getDateTimeInstance(
            DateFormat.FULL,
            DateFormat.FULL,
        )
        assert(longTimeStamp.format(Date()).isNotEmpty())

        //utilisez java.text.SimpleDateFormat
        //pour définir votre propre modele de formatage
        val customFormat = SimpleDateFormat(&amp;quot;yyyy.MM.dd&amp;quot;)
        assertEquals(10, customFormat.format(Date()).length)

        //DateFormat peut également parser les date contenu dans des chaines
        val kotlinAnnounceDate = customFormat.parse(&amp;quot;2019.05.08&amp;quot;)

        //la class Date et sa représentation en millisecondes
        //n&amp;#39;autorise qu&amp;#39;une forme trés simple d&amp;#39;arithmétique
        //on ajoute 3 600 000 millisecondes à l&amp;#39;heure courante
        val anHourFromNow = now.getTime() + (60 * 60 * 1000)
        assert(anHourFromNow &amp;amp;gt; now.getTime())

        //java.util.Calendar
        //pour manipuler les dates et heures de facon plus sophistiquée
        //instanciation selon les parametres locaux
        //et le fuseau horaire local
        val calendar = Calendar.getInstance()
        //initialisation du calendrier à la date de maintenant
        calendar.setTime(now)
        //détermine le jour de l&amp;#39;année auquel correspond la date courante
        val dayOfYear = calendar.get(Calendar.DAY_OF_YEAR)
        assert(dayOfYear &amp;amp;lt; 366)
        //réinitialisation de la date courante
        calendar.set(2019, Calendar.MAY, 8)
        assertEquals(4, calendar.get(Calendar.DAY_OF_WEEK))

        //à quel jour du mois correspond le deuxieme mercredi de mai 2019
        //set(key,value)
        calendar.set(Calendar.YEAR, 2019)
        calendar.set(Calendar.MONTH, Calendar.MAY)
        calendar.set(Calendar.DAY_OF_WEEK, Calendar.WEDNESDAY)
        //defini à quel (n=2) semaine du mois est la date
        calendar.set(Calendar.DAY_OF_WEEK_IN_MONTH, 2)
        //extrait le jour du mois
        val dayOfMonth = calendar.get(Calendar.DAY_OF_MONTH)
        assertEquals(8, dayOfMonth)

        calendar.setTime(kotlinAnnounceDate)
        //ajoute 30j à la date
        calendar.add(Calendar.DATE, 30)
        val monthAfter = calendar.getTime()
        //date est elle avant ou apres?
        assertTrue(monthAfter.after(kotlinAnnounceDate))
    }
}&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;#toc&amp;quot;&amp;gt;目次&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;java8date&amp;quot;&amp;gt;日付と時刻 java8&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;Java 8 は新しいパッケージ &amp;lt;code&amp;gt;&amp;lt;em&amp;gt;*java.time&amp;lt;/em&amp;gt;*&amp;lt;/code&amp;gt; を導入し、基本クラスを含んでいる&amp;lt;br&amp;gt;
ほとんどの開発者は作業しています。 また、4つのサブパッケージが含まれています：&amp;lt;br&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;&amp;lt;em&amp;gt;java.time.chrono&amp;lt;/em&amp;gt;&amp;lt;/strong&amp;gt;&amp;lt;br&amp;gt;
開発者が使用しているカレンダーシステムに関する代替の年表&amp;lt;br&amp;gt;
ISO規格に従うことは相互作用するでしょう 例としては日本のカレンダーです&amp;lt;br&amp;gt;
耐久性のあるシステム。&amp;lt;br&amp;gt;
&amp;lt;strong&amp;gt;&amp;lt;em&amp;gt;java.time.format&amp;lt;/em&amp;gt;&amp;lt;/strong&amp;gt;&amp;lt;br&amp;gt;
日付と時刻のオブジェクトを変換するために使用されるDateTimeFormatterを含む&amp;lt;br&amp;gt;
文字列中、およびデータおよび時刻オブジェクト内の文字列を分析するためにも&amp;lt;br&amp;gt;
&amp;lt;strong&amp;gt;&amp;lt;em&amp;gt;java.time.temporal&amp;lt;/em&amp;gt;&amp;lt;/strong&amp;gt;&amp;lt;br&amp;gt;
ベースの日付と時刻クラスに必要なインターフェイスを含み、さらに&amp;lt;br&amp;gt;
抽象（クエリや調整子など）を用いた、日付に関する高度な操作。&amp;lt;br&amp;gt;
&amp;lt;strong&amp;gt;&amp;lt;em&amp;gt;java.time.zone&amp;lt;/em&amp;gt;&amp;lt;/strong&amp;gt;&amp;lt;br&amp;gt;
基盤となるタイムゾーンルールに使用されるクラス;&amp;lt;br&amp;gt;
ほとんどの開発者はこのパッケージが必要ないでしょう。&amp;lt;br&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;imageblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;img src=&amp;quot;../../img/java8-date-time.png&amp;quot; alt=&amp;quot;java8 date time&amp;quot;&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-kotlin hljs&amp;quot; data-lang=&amp;quot;kotlin&amp;quot;&amp;gt;import java.time.LocalDate
import java.time.Month
import java.time.Period
import java.time.YearMonth
import java.time.temporal.*
import java.util.HashMap
import java.util.stream.Collectors
import kotlin.test.Test

class DatesHoursJava8Test {
    class BirthdayDiary {
        private val birthdays: MutableMap&amp;amp;lt;String, LocalDate&amp;amp;gt;

        init {
            birthdays = HashMap()
        }

        fun addBirthday(
            name: String, day: Int, month: Int,
            year: Int
        ): LocalDate {
            val birthday: LocalDate = LocalDate.of(year, month, day)
            birthdays[name] = birthday
            return birthday
        }

        fun getBirthdayFor(name: String): LocalDate? {
            return birthdays[name]
        }

        fun getAgeInYear(name: String, year: Int): Int {
            val period: Period = Period.between(
                birthdays[name],
                birthdays[name]!!.withYear(year)
            )
            return period.getYears()
        }

        fun getFriendsOfAgeIn(age: Int, year: Int): Set&amp;amp;lt;String&amp;amp;gt; {
            return birthdays.keys.stream()
                .filter { p: String -&amp;amp;gt; getAgeInYear(p, year) == age }
                .collect(Collectors.toSet())
        }

        fun getDaysUntilBirthday(name: String): Int {
            val period: Period = Period.between(
                LocalDate.now(),
                birthdays[name]
            )
            return period.getDays()
        }

        fun getBirthdaysIn(month: Month): Set&amp;amp;lt;String&amp;amp;gt; {
            return birthdays.entries.stream()
                .filter { (_, value): Map.Entry&amp;amp;lt;String, LocalDate&amp;amp;gt; -&amp;amp;gt; value.getMonth() === month }
                .map&amp;amp;lt;String&amp;amp;gt; { (key): Map.Entry&amp;amp;lt;String, LocalDate&amp;amp;gt; -&amp;amp;gt; key }
                .collect(Collectors.toSet())
        }

        val birthdaysInCurrentMonth: Set&amp;amp;lt;String&amp;amp;gt;
            get() = getBirthdaysIn(LocalDate.now().getMonth())
        val totalAgeInYears: Int
            get() = birthdays.keys.stream()
                .mapToInt { p: String -&amp;amp;gt;
                    getAgeInYear(
                        p,
                        LocalDate.now().getYear()
                    )
                }
                .sum()
    }

    //Les ajusteurs modifient les objets de date et d&amp;#39;heure. Supposons, par exemple, que nous voulions
    //renvoie le premier jour d&amp;#39;un trimestre qui contient un horodatage particulier :
    class FirstDayOfQuarter : TemporalAdjuster {
        override fun adjustInto(temporal: Temporal): Temporal? {
            val currentQuarter: Int = YearMonth.from(temporal)
                .get(IsoFields.QUARTER_OF_YEAR)
            return when (currentQuarter) {
                1 -&amp;amp;gt; LocalDate.from(temporal)
                    .with(TemporalAdjusters.firstDayOfYear())

                2 -&amp;amp;gt; LocalDate.from(temporal)
                    .withMonth(Month.APRIL.value)
                    .with(TemporalAdjusters.firstDayOfMonth())

                3 -&amp;amp;gt; LocalDate.from(temporal)
                    .withMonth(Month.JULY.value)
                    .with(TemporalAdjusters.firstDayOfMonth())

                4 -&amp;amp;gt; LocalDate.from(temporal)
                    .withMonth(Month.OCTOBER.value)
                    .with(TemporalAdjusters.firstDayOfMonth())

                else -&amp;amp;gt; null
            }
        }
    }

    enum class Quarter {
        FIRST, SECOND, THIRD, FOURTH
    }

    //Dans quel trimestre de l&amp;#39;année cette date se situe-t-elle ?
    class QuarterOfYearQuery : TemporalQuery&amp;amp;lt;Quarter&amp;amp;gt; {
        override fun queryFrom(temporal: TemporalAccessor): Quarter {
            val now = LocalDate.from(temporal)
            return if (now.isBefore(now.with(Month.APRIL).withDayOfMonth(1)))
                Quarter.FIRST
            else if (now.isBefore(
                    now.with(Month.JULY)
                        .withDayOfMonth(1)
                )
            ) Quarter.SECOND else if (now.isBefore(
                    now.with(Month.NOVEMBER)
                        .withDayOfMonth(1)
                )
            ) Quarter.THIRD else Quarter.FOURTH
        }
    }

    @Test
    fun `Dates et heures après java 8`() {
        val today = LocalDate.now()
        val currentMonth = today.month
        val firstMonthOfQuarter = currentMonth.firstMonthOfQuarter()

        val q = QuarterOfYearQuery()
        // Direct
        var quarter: Quarter? = q.queryFrom(LocalDate.now())
        println(quarter)
        // Indirect
        quarter = LocalDate.now().query(q)
        println(quarter)


        val now = LocalDate.now()
        val fdoq: Temporal = now.with(FirstDayOfQuarter())
        println(fdoq)
    }
}&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;#toc&amp;quot;&amp;gt;目次&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;arrCol&amp;quot;&amp;gt;配列とコレクション&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;imageblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;img src=&amp;quot;../../img/collections_classes_inheritance.png&amp;quot; alt=&amp;quot;Classes de collections et héritage&amp;quot;&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-kotlin hljs&amp;quot; data-lang=&amp;quot;kotlin&amp;quot;&amp;gt;package playground.programming

import java.util.*
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertFalse
import kotlin.test.assertTrue

class ArrayCollectionTest {
    @Test
    fun `Tableaux, collections`() {
        //Tableau
        //java.util.Arrays définit d&amp;#39;utiles méthodes de manipulation de tableaux,
        //y compris de tri et de recherche au sein d&amp;#39;un tableau
        val intArray = arrayOf(10, 5, 7, -3)
        //tri le tableau
        Arrays.sort(intArray)
        var pos = Arrays.binarySearch(intArray, 7)
        //la valeur 7 est trouvé a l&amp;#39;index 2
        assertEquals(2, pos)
        //12 pas trouvé retourne une valeur negative
        assert(Arrays.binarySearch(intArray, 12) &amp;amp;lt; 0)

        //les tableaux peuvent également etre triés
        //et faire l&amp;#39;objet d&amp;#39;une recherche
        val stringArray = arrayOf(&amp;quot;le&amp;quot;, &amp;quot;moment&amp;quot;, &amp;quot;c&amp;#39;est&amp;quot;)
        assertEquals(&amp;quot;c&amp;#39;est&amp;quot;, stringArray[2])
        assertEquals(&amp;quot;le&amp;quot;, stringArray[0])
        assertEquals(&amp;quot;moment&amp;quot;, stringArray[1])
        Arrays.sort(stringArray)
        assertEquals(&amp;quot;c&amp;#39;est&amp;quot;, stringArray[0])
        assertEquals(&amp;quot;le&amp;quot;, stringArray[1])
        assertEquals(&amp;quot;moment&amp;quot;, stringArray[2])

        //Arrays.equals() compare tous les éléments de deux tableaux
        //Arrays.clone() copie tous les elements du tableau dans un autre
        stringArray.forEachIndexed { i, it -&amp;amp;gt; assertEquals(it, stringArray.clone()[i]) }

        val data = ByteArray(100)
        //Arrays.fill() initialise tous les éléments des deux tableaux
        //initalise tous les éléments à -1
        Arrays.fill(data, -1)
        data.forEach { assertEquals(-1, it) }

        //attribue aux éléments 5, 6, 7, 8 et 9 la valeur -2
        Arrays.fill(data, 5, 10, -2)
        ((5 until (10 - 1))).forEach { assertEquals(-2, data[it]) }

        //récupère le type de data
        val type = data::class.java
        //est ce que data est un tableau?
        assertTrue(type.isArray())
        //est ce que data est un tableau de byte
        assertEquals(Byte::class.java, type.getComponentType())

        //Collection
        val s = java.util.HashSet&amp;amp;lt;String&amp;amp;gt;()
        s.add(&amp;quot;test&amp;quot;)
        assertTrue(s.contains(&amp;quot;test&amp;quot;))
        assertFalse(s.contains(&amp;quot;test2&amp;quot;))
        s.remove(&amp;quot;test&amp;quot;)
        assertFalse(s.contains(&amp;quot;test&amp;quot;))

        val ss = TreeSet&amp;amp;lt;String&amp;amp;gt;()
        ss.add(&amp;quot;b&amp;quot;)
        ss.add(&amp;quot;a&amp;quot;)
        ss.iterator().forEach { assertTrue(it == &amp;quot;a&amp;quot; || it == &amp;quot;b&amp;quot;) }

        //liste doublement chainée
        var dll: List&amp;amp;lt;String&amp;amp;gt; = LinkedList&amp;amp;lt;String&amp;amp;gt;()

        //plus efficace
        val l = java.util.ArrayList&amp;amp;lt;String&amp;amp;gt;()
        l.addAll(ss)
        l.addAll(1, ss)

        val obj = l.get(1)
        val obj_prime = l[1]
        assertEquals(obj, obj_prime)

        l.set(3, &amp;quot;nouvel élément&amp;quot;)
        l.add(&amp;quot;test&amp;quot;)
        l.add(0, &amp;quot;test2&amp;quot;)
        l.removeAt(1)
        l.remove(&amp;quot;a&amp;quot;)
        assertFalse(l.contains(&amp;quot;a&amp;quot;))
        l.removeAll(ss)
        assertFalse(l.containsAll(ss))
        assertFalse(l.isEmpty())
        assertTrue(l.isNotEmpty())


        val sublist = l.subList(1, 3)
        val elements = l.toArray()
        l.clear()

        val m = HashMap&amp;amp;lt;String, Integer&amp;amp;gt;()
        m.put(&amp;quot;clé&amp;quot;, Integer(42))
        m[&amp;quot;clé&amp;quot;] = Integer(42)
        val value: Integer = m.get(&amp;quot;clé&amp;quot;)!!
        assertEquals(Integer(42), value)
        m.remove(&amp;quot;clé&amp;quot;)
        assertTrue(m.isEmpty())
        val keys = m.keys
        assertTrue(keys.isEmpty())


        val set = HashSet&amp;amp;lt;String&amp;amp;gt;()
        set.add(&amp;quot;key_1&amp;quot;)
        set.add(&amp;quot;key_2&amp;quot;)
        set.add(&amp;quot;key_3&amp;quot;)
        val members = set.toArray()
        assertEquals(3, members.size)
        val list = ArrayList&amp;amp;lt;String&amp;amp;gt;()
        list.add(&amp;quot;items1&amp;quot;)
        list.add(&amp;quot;items2&amp;quot;)
        list.add(&amp;quot;items3&amp;quot;)
        val items = list.toArray()
        assertEquals(3, items.size)

        //trie et recherche d&amp;#39;éléments sur les collections
        list.add(&amp;quot;clé&amp;quot;)
        //en premier on trie
        Collections.sort(list)
        //en kotlin
        list.sort()
        //en deuxieme on cherche
        //retourne l&amp;#39;index du premier trouvé sinon -1
        pos = Collections.binarySearch(list, &amp;quot;clé&amp;quot;)
        assertEquals(0, pos)
        val list1 = mutableListOf(1, 2, 3, 4, 5)
        val list2 = mutableListOf&amp;amp;lt;Int&amp;amp;gt;(0, 0, 0, 0, 0)

        //d&amp;#39;autres méthodes intéressantes concernant Collections

        //copie list1 dans list2, 2e parametre dans 1er parametre
        Collections.copy(list2, list1)
        //comparaison de la copy avec filter
        assertTrue(list1.filterIndexed { i: Int, it: Int -&amp;amp;gt; it != list2[i] }.isEmpty())
        //comparaison de la copy avec map
        list1.mapIndexed { index: Int, it: Int -&amp;amp;gt; assertEquals(it, list2[index]) }

        //rempli avec des 0
        Collections.fill(list2, 0)
        assertTrue(list2.none { it != 0 })

        //le maximum
        assertEquals(5, Collections.max(list1))

        //le minimum
        assertEquals(1, Collections.min(list1))

        //renverse
        Collections.reverse(list)
        listOf(&amp;quot;items3&amp;quot;, &amp;quot;items2&amp;quot;, &amp;quot;items1&amp;quot;, &amp;quot;clé&amp;quot;).mapIndexed { i: Int, it: String -&amp;amp;gt; assertEquals(it, list[i]) }

        //mélange la list
        Collections.shuffle(list)

        //retourne un ensemble immuable possédant un seul élément 0
        Collections.singleton(0)
        //renvoi un emballage immuable autour d&amp;#39;une liste
        Collections.unmodifiableList(list)
        //renvoi un emballage synchronisé autour d&amp;#39;une map, ensemble clé valeur
        Collections.synchronizedMap(m)

        //java.util.Properties un est objet key value
    }
}&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;#toc&amp;quot;&amp;gt;目次&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;sysProp&amp;quot;&amp;gt;System.Properties&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;https://docs.oracle.com/javase/tutorial/essential/environment/sysprop.html&amp;quot;&amp;gt;System.Properties 公式ドキュメント&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;ここにいくつかの興味深いプロパティの表があります。&amp;lt;br&amp;gt;
これらの特性は情報を得るために興味深いです&amp;lt;br&amp;gt;
JVMのホストシステム上で&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;table class=&amp;quot;tableblock frame-all grid-all stretch&amp;quot;&amp;gt;
&amp;lt;colgroup&amp;gt;
&amp;lt;col style=&amp;quot;width: 3.3333%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 3.3333%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 3.3333%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 3.3333%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 3.3333%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 3.3333%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 3.3333%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 3.3333%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 3.3333%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 3.3333%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 3.3333%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 3.3333%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 3.3333%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 3.3333%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 3.3333%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 3.3333%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 3.3333%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 3.3333%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 3.3333%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 3.3333%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 3.3333%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 3.3333%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 3.3333%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 3.3333%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 3.3333%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 3.3333%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 3.3333%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 3.3333%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 3.3333%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 3.3343%;&amp;quot;&amp;gt;
&amp;lt;/colgroup&amp;gt;
&amp;lt;tbody&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;キー&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;意味&amp;lt;/strong&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;ファイルセパレータ&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;ファイルパスのコンポーネントを区切る文字。これはUNIXでは&amp;quot;/&amp;quot;、Windowsでは&amp;quot;\&amp;quot;です。&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;java.class.path&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;クラスファイルを含むディレクトリおよびJARアーカイブを見つけるために使用されるパス。クラスパスの要素は、&amp;lt;code&amp;gt;path.separator&amp;lt;/code&amp;gt; プロパティで指定されるプラットフォーム固有の文字で区切られます。&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;java.home&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;Java Runtime Environment (JRE) のインストールディレクトリ&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;java.vendor&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;JRE ベンダー名&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;Java ベンダーの URL&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;JREベンダーURL&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;java.version&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;JREバージョン番号&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;line.separator&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;オペレーティングシステムがテキストファイルの行を区切るために使用するシーケンス&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;os.arch&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;オペレーティング システム アーキテクチャ&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;os.name&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;オペレーティングシステム名&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;os.version&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;オペレーティングシステムのバージョン&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;パス区切り文字&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;java.class.path で使用されるパス区切り文字&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;user.dir&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;作業ディレクトリ&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;user.home&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;ユー�ーザーのホームディレクトリ&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;ユーザー名&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;ユーザーアカウント名&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/tbody&amp;gt;
&amp;lt;/table&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;#toc&amp;quot;&amp;gt;目次&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;threads&amp;quot;&amp;gt;スレッド&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-kotlin hljs&amp;quot; data-lang=&amp;quot;kotlin&amp;quot;&amp;gt;import java.text.DateFormat
import java.util.*
import kotlin.test.Test

class ThreadsTest {

    @Test
    fun `threads test`() {
        //java.lang.Thread représente le thread fondamentale de l&amp;#39;API java
        //il existe deux manière de définir un thread
        //1) étendre la classe Thread ou une lambda en kotlin
        //2) implémenter l&amp;#39;interface Runnable,
        //      puis passer une instance de cet objet Runnable au constructeur de Thread.

        val list1: List&amp;amp;lt;Int&amp;amp;gt; = List(
            size = 45,
            init = { (1..31).random() }
        )
        println(&amp;quot;list1$list1&amp;quot;)
        //facon 1
        val t = Thread {
            Collections.sort(list1)
            println(&amp;quot;list1 sorted$list1&amp;quot;)
        }
        t.start()

        val list2 = List(
            size = 45,
            init = { (1..31).random() }
        )
        println(&amp;quot;list2$list2&amp;quot;)
        //facon 2
        val sorter = BackgroundSorter(list2)
        sorter.start()

        //priorité des threads
        //tant qu&amp;#39;un thread de niveau de priorité supérieure n&amp;#39;est pas fini
        //alors celui de niveau inférieur ne peut s&amp;#39;exécuter

        //on définit un thread avec une priorité inférieur à la normale
        t.setPriority(Thread.NORM_PRIORITY - 1)

        //ici on définit un thread avec une priorité inférieur à la priorité
        //du thread courant
        t.setPriority(Thread.currentThread().getPriority() - 1)

        //Thread.yield() fait une pause pour laisser les autres threads de meme priorité s&amp;#39;exécuter
    }

    class BackgroundSorter(private val l: List&amp;amp;lt;Int&amp;amp;gt;) : Thread() {
        override fun run() {
            Collections.sort(l)
            println(&amp;quot;list2 sorted$l&amp;quot;)
        }
    }

    //pour l&amp;#39;arrêt du thread, plutôt qu&amp;#39;utiliser la fonction Thread.stop()
    // qui laisse la memoire dans un état non controlé.
    //utiliser la méthode tel que l&amp;#39;exemple pleaseStop()
    class DummyClock(
        private val df: DateFormat = DateFormat.getTimeInstance(DateFormat.MEDIUM),
        private var keepRunning: Boolean = true
    ) : Thread() {
        init {
            isDaemon = true
            start()
        }

        override fun run() {
            while (keepRunning) {
                println(df.format(Date()))
                try {
                    sleep(1000)
                } catch (e: InterruptedException) {
                    println(e.message)
                }
            }
        }

        fun pleaseStop() {
            keepRunning = false
        }
    }

    //java.util.Timer
    //java.util.TimerTask
    //ces classes permettent l&amp;#39;exécution de taches répétitives
    @Test
    fun `Timer et TimerTask test`() {
        DummyClock()
    }
}&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;#toc&amp;quot;&amp;gt;目次&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;regex&amp;quot;&amp;gt;正規表現&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-kotlin hljs&amp;quot; data-lang=&amp;quot;kotlin&amp;quot;&amp;gt;import java.util.*
import java.util.regex.Matcher
import java.util.regex.Pattern
import java.util.stream.Collectors
import kotlin.test.Test
import kotlin.test.assertEquals

class RegularExpressionsTest {
    @Test
    fun `expressions régulières`() {
        val p: Pattern = Pattern.compile(&amp;quot;honou?r&amp;quot;)
        val caesarUK = &amp;quot;For Brutus is an honourable man&amp;quot;
        val mUK: Matcher = p.matcher(caesarUK)
        assertEquals(true, mUK.find(), &amp;quot;Should matches UK spelling&amp;quot;)
        val caesarUS = &amp;quot;For Brutus is an honorable man&amp;quot;
        val mUS: Matcher = p.matcher(caesarUS)
        assertEquals(true, mUS.find(), &amp;quot;Should matches US spelling&amp;quot;)
    }

    @Test
    fun `expressions régulières plus complexes`() {
        //Notez que nous devons utiliser \\ car nous avons besoin d&amp;#39;un littéral \
        //et Java utilise un seul \ comme caractère d&amp;#39;échappement
        var pStr = &amp;quot;\\d&amp;quot; // Un chiffre numérique

        var text = &amp;quot;Apollo 13&amp;quot;
        var p = Pattern.compile(pStr)
        var m = p.matcher(text)
        print(pStr + &amp;quot; matches &amp;quot; + text + &amp;quot;? &amp;quot; + m.find())
        println(&amp;quot; ; match: &amp;quot; + m.group())
        pStr = &amp;quot;[a..zA..Z]&amp;quot; //N&amp;#39;importe quelle lettre

        p = Pattern.compile(pStr)
        m = p.matcher(text)
        print(pStr + &amp;quot; matches &amp;quot; + text + &amp;quot;? &amp;quot; + m.find())
        println(&amp;quot; ; match: &amp;quot; + m.group())

        //N&amp;#39;importe quel nombre de lettres, qui doivent toutes être comprises entre &amp;#39;a&amp;#39; et &amp;#39;j&amp;#39;
        //mais peut-être en majuscule ou en minuscule.
        pStr = &amp;quot;([a..jA..J]*)&amp;quot;
        p = Pattern.compile(pStr)
        m = p.matcher(text)
        print(pStr + &amp;quot; matches &amp;quot; + text + &amp;quot;? &amp;quot; + m.find())
        println(&amp;quot; ; match: &amp;quot; + m.group())
        text = &amp;quot;abacab&amp;quot;
        //&amp;#39;a&amp;#39; suivi de quatre caractères quelconques, suivi de &amp;#39;b&amp;#39;
        pStr = &amp;quot;a....b&amp;quot;
        p = Pattern.compile(pStr)
        m = p.matcher(text)
        print(pStr + &amp;quot; matches &amp;quot; + text + &amp;quot;? &amp;quot; + m.find())
        println(&amp;quot; ; match: &amp;quot; + m.group())
    }

    @Test
    fun `Quelles chaînes correspondent à la regex ?`() {
        val pStr = &amp;quot;\\d&amp;quot; // Un chiffre numérique
        val p = Pattern.compile(pStr)
        val ls: List&amp;amp;lt;String&amp;amp;gt; = Arrays.asList(&amp;quot;Cat&amp;quot;, &amp;quot;Dog&amp;quot;, &amp;quot;Ice-9&amp;quot;, &amp;quot;99 Luftballoons&amp;quot;)
        val containDigits: List&amp;amp;lt;String&amp;amp;gt; = ls.stream()
            .filter(p.asPredicate())
            .collect(Collectors.toList())
        assert(containDigits.contains(&amp;quot;Ice-9&amp;quot;))
        assert(containDigits.contains(&amp;quot;99 Luftballoons&amp;quot;))
        assertEquals(2, containDigits.size)
    }
}&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_表_regex_metacharacters&amp;quot;&amp;gt;表 regex metacharacters&amp;lt;/h3&amp;gt;
&amp;lt;table class=&amp;quot;tableblock frame-all grid-all stretch&amp;quot;&amp;gt;
&amp;lt;colgroup&amp;gt;
&amp;lt;col style=&amp;quot;width: 1.7543%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 1.7543%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 1.7543%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 1.7543%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 1.7543%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 1.7543%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 1.7543%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 1.7543%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 1.7543%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 1.7543%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 1.7543%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 1.7543%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 1.7543%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 1.7543%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 1.7543%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 1.7543%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 1.7543%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 1.7543%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 1.7543%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 1.7543%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 1.7543%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 1.7543%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 1.7543%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 1.7543%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 1.7543%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 1.7543%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 1.7543%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 1.7543%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 1.7543%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 1.7543%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 1.7543%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 1.7543%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 1.7543%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 1.7543%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 1.7543%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 1.7543%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 1.7543%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 1.7543%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 1.7543%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 1.7543%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 1.7543%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 1.7543%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 1.7543%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 1.7543%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 1.7543%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 1.7543%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 1.7543%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 1.7543%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 1.7543%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 1.7543%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 1.7543%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 1.7543%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 1.7543%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 1.7543%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 1.7543%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 1.7543%;&amp;quot;&amp;gt;
&amp;lt;col style=&amp;quot;width: 1.7592%;&amp;quot;&amp;gt;
&amp;lt;/colgroup&amp;gt;
&amp;lt;tbody&amp;gt;
&amp;lt;tr&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;メタ文字&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;機能性&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;ノート&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;?&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;オプションの文字—ゼロまたは1つのインスタンス&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;*&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;直前の文字のゼロ回以上&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;+&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;1つ以上の前の文字&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;{M,N}&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;前の文字のMからN回&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;\d&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;一つの数字&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;\D&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;数字以外の文字&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;\w&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;単語の文字&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;数字、文字、および_&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;\W&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;言葉のない文字&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;\s&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;スペース文字&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;\S&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;非空白文字&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;\n&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;改行文字&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;\t&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;タブ文字&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;。&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;任意の文字&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;Javaでは改行を含みません&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;[Translation of empty string is empty string]&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;角括弧で囲まれたすべての文字&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;文字クラスが呼び出された&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;[^ ]&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;角括弧内に含まれない任意の文字&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;逆順文字クラスと呼ばれた&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;( )&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;パターンの要素のグループを構築する&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;グループ（またはキャプチャーグループ）と呼ばれる&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;|&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;代替の可能性を定義する&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;論理的なORを実装&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;^&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;p class=&amp;quot;tableblock&amp;quot;&amp;gt;文字列の開始 $ 文字列の終了&amp;lt;/p&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;td class=&amp;quot;tableblock halign-left valign-top&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;
&amp;lt;/tbody&amp;gt;
&amp;lt;/table&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;完了するhttps://www.codeurjava.com/2015/05/les-expressions-regulieres-avec-regex.html[と]&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;</description>
        </item><item>
            <title>Gradleメモ</title>
            <link >https://cheroliv.com/blog/2022/0047_memo_gradle_post.html</link>
            <pubDate>Mon, 23 May 2022 00:00:00 +0000</pubDate>
            <guid isPermaLink="false">blog/2022/0047_memo_gradle_post.html</guid>
            <description>&amp;lt;div id=&amp;quot;toc&amp;quot; class=&amp;quot;toc&amp;quot;&amp;gt;
&amp;lt;div id=&amp;quot;toctitle&amp;quot;&amp;gt;Sommaire&amp;lt;/div&amp;gt;
&amp;lt;ul class=&amp;quot;sectlevel1&amp;quot;&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_ヘルプを表示&amp;quot;&amp;gt;ヘルプを表示&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_jvmのシステムプロパティを設定する_d_system_prop&amp;quot;&amp;gt;JVMのシステムプロパティを設定する : `-D, --system-prop&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_ビルドスクリプトのプロジェクトプロパティを設定する_pmypropmyvalue&amp;quot;&amp;gt;ビルドスクリプトのプロジェクトプロパティを設定する: `-Pmyprop=myvalue&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_gradleの起動ディレクトリを指定しますデフォルトは現在のディレクトリです&amp;quot;&amp;gt;Gradleの起動ディレクトリを指定します。デフォルトは現在のディレクトリです。&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_コマンドラインからプロパティ_param_component_をオーバーライドする&amp;quot;&amp;gt;コマンドラインからプロパティ &amp;#39;param_component&amp;#39; をオーバーライドする :&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_通常のプロジェクトで_kotlin_dsl_を使用してソースセットにフォルダーを追加する&amp;quot;&amp;gt;通常のプロジェクトで Kotlin DSL を使用してソースセットにフォルダーを追加する&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_groovy_dsl_を使って_android_プロジェクトのソースセットにフォルダーを追加する&amp;quot;&amp;gt;Groovy DSL を使って Android プロジェクトのソースセットにフォルダーを追加する&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_サブモジュールの構築とテストを避ける&amp;quot;&amp;gt;サブモジュールの構築とテストを避ける&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_ファイルを取る&amp;quot;&amp;gt;ファイルを取る&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_ビルドの依存関係を表示&amp;quot;&amp;gt;ビルドの依存関係を表示&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_reduceの使用例リストの文字列への結合&amp;quot;&amp;gt;reduceの使用例：リストの文字列への結合&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_特定のタスクの説明を取得&amp;quot;&amp;gt;特定のタスクの説明を取得&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_workingdir_ルートからタスクを起動するにはタスクに_をプレフィックスとして付けてください&amp;quot;&amp;gt;workingDir ルートからタスクを起動するには、タスクに &amp;lt;code&amp;gt;:&amp;lt;/code&amp;gt; をプレフィックスとして付けてください。&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_失敗したタスクを再起動するにはオプション_rerun_tasks_を使用してください&amp;quot;&amp;gt;失敗したタスクを再起動するには、オプション &amp;lt;code&amp;gt;--rerun-tasks&amp;lt;/code&amp;gt; を使用してください。&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;#_別のディレクトリから特定のプロジェクトでタスクを起動する&amp;quot;&amp;gt;別のディレクトリから特定のプロジェクトでタスクを起動する&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_ヘルプを表示&amp;quot;&amp;gt;ヘルプを表示&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;./gradlew --help&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_jvmのシステムプロパティを設定する_d_system_prop&amp;quot;&amp;gt;JVMのシステムプロパティを設定する : `-D, --system-prop&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;./gradlew -Dmyprop=myvalue
#ou
./gradlew --system-prop myvalue&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_ビルドスクリプトのプロジェクトプロパティを設定する_pmypropmyvalue&amp;quot;&amp;gt;ビルドスクリプトのプロジェクトプロパティを設定する: `-Pmyprop=myvalue&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;./gradlew -Pmyprop=myvalue
#ou
./gradlew --project-prop myvalue&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_gradleの起動ディレクトリを指定しますデフォルトは現在のディレクトリです&amp;quot;&amp;gt;Gradleの起動ディレクトリを指定します。デフォルトは現在のディレクトリです。&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;./gradlew -p ~/src/next_startup
#ou
./gradlew --project-dir ~/src/next_startup&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_コマンドラインからプロパティ_param_component_をオーバーライドする&amp;quot;&amp;gt;コマンドラインからプロパティ &amp;#39;param_component&amp;#39; をオーバーライドする :&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;./gradlew -Pparam_component=CUSTOM_VALUE&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_通常のプロジェクトで_kotlin_dsl_を使用してソースセットにフォルダーを追加する&amp;quot;&amp;gt;通常のプロジェクトで Kotlin DSL を使用してソースセットにフォルダーを追加する&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-kotlin hljs&amp;quot; data-lang=&amp;quot;kotlin&amp;quot;&amp;gt;sourceSets {
    getByName(&amp;quot;test&amp;quot;){
        java.srcDir(&amp;quot;src/scripts/groovy&amp;quot;)
    }
    getByName(&amp;quot;test&amp;quot;){
        java.srcDir(&amp;quot;src/scripts/kscript&amp;quot;)
    }
    getByName(&amp;quot;test&amp;quot;){
        java.srcDir(&amp;quot;src/test/javascript&amp;quot;)
    }
}&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_groovy_dsl_を使って_android_プロジェクトのソースセットにフォルダーを追加する&amp;quot;&amp;gt;Groovy DSL を使って Android プロジェクトのソースセットにフォルダーを追加する&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-kotlin hljs&amp;quot; data-lang=&amp;quot;kotlin&amp;quot;&amp;gt;android {
    sourceSets {
        main.java.srcDirs += &amp;quot;src/main/../../../../ceelo/domain/src/main/java/&amp;quot;
        test.java.srcDirs += &amp;quot;src/test/../../../../ceelo/domain/src/test/java/&amp;quot;
    }
}&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_サブモジュールの構築とテストを避ける&amp;quot;&amp;gt;サブモジュールの構築とテストを避ける&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;Gradle ビルド -x :excluded-module:check -x :excluded-module:assemble -x :excluded-module:build&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;ファイルを移動する&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-kotlin hljs&amp;quot; data-lang=&amp;quot;kotlin&amp;quot;&amp;gt;tasks.register(&amp;quot;moveWebappNode&amp;quot;) {
    doLast {
        ant.withGroovyBuilder {
            &amp;quot;move&amp;quot;(
                &amp;quot;webapp/node_modules&amp;quot; to &amp;quot;$rootDir/webapp-src/node_modules&amp;quot;,
            )
        }
    }
}&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_ファイルを取る&amp;quot;&amp;gt;ファイルを取る&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-kotlin hljs&amp;quot; data-lang=&amp;quot;kotlin&amp;quot;&amp;gt;tasks.register&amp;amp;lt;Tar&amp;amp;gt;(&amp;quot;tarWebapp&amp;quot;) {
    dependsOn(&amp;quot;moveWebappNpm&amp;quot;)
    group = WEBAPP
    description = &amp;quot;tar webapp&amp;quot;
    doLast {
        setOf(
            &amp;quot;build&amp;quot;,
            &amp;quot;target&amp;quot;,
            &amp;quot;node_modules&amp;quot;
        ).forEach { dir -&amp;amp;gt; exclude { it.name .dir } }
        archiveFileName.set(&amp;quot;webapp.tar&amp;quot;)
        destinationDirectory.set(File(&amp;quot;${rootDir.absolutePath}$sep$WEBAPP_SRC&amp;quot;))
    }
}&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_ビルドの依存関係を表示&amp;quot;&amp;gt;ビルドの依存関係を表示&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-kotlin hljs&amp;quot; data-lang=&amp;quot;kotlin&amp;quot;&amp;gt;tasks.register(&amp;quot;printDependencies&amp;quot;) {
    description = &amp;quot;print project dependencies&amp;quot;
    group = WEBAPP
    doLast {
        println(&amp;quot;${project.name} dependencies&amp;quot;)
        mutableMapOf&amp;amp;lt;String, Map&amp;amp;lt;String, String&amp;amp;gt;&amp;amp;gt;(
            &amp;quot;buildDependencies&amp;quot; to buildDependencies,
            &amp;quot;domainDeps&amp;quot; to domainDeps,
            &amp;quot;domainTestDeps&amp;quot; to domainTestDeps,
        ).apply { putAll(appModules) }
            .forEach { module -&amp;amp;gt;
                if (module.value.isNotEmpty()) {
                    println(&amp;quot;${module.key}:&amp;quot;)
                    module.value.forEach { println(dependency(it)) }
                    println()
                }
            }
    }
}&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_reduceの使用例リストの文字列への結合&amp;quot;&amp;gt;reduceの使用例：リストの文字列への結合&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-kotlin hljs&amp;quot; data-lang=&amp;quot;kotlin&amp;quot;&amp;gt;tasks.register(&amp;quot;printWebappSrc&amp;quot;) {
    description = &amp;quot;print webapp sources&amp;quot;
    group = WEBAPP
    doLast {
        webAppSrc
            .reduce { acc, s -&amp;amp;gt; &amp;quot;$acc\n\t$s&amp;quot; }
            .run { println(&amp;quot;$WEBAPP_SRC: $this\n&amp;quot;) }
    }
}&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_特定のタスクの説明を取得&amp;quot;&amp;gt;特定のタスクの説明を取得&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;./gradlew -q help --task foo&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_workingdir_ルートからタスクを起動するにはタスクに_をプレフィックスとして付けてください&amp;quot;&amp;gt;workingDir ルートからタスクを起動するには、タスクに &amp;lt;code&amp;gt;:&amp;lt;/code&amp;gt; をプレフィックスとして付けてください。&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;./gradlew :foo&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_失敗したタスクを再起動するにはオプション_rerun_tasks_を使用してください&amp;quot;&amp;gt;失敗したタスクを再起動するには、オプション &amp;lt;code&amp;gt;--rerun-tasks&amp;lt;/code&amp;gt; を使用してください。&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;./gradlew check --rerun-tasks&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_別のディレクトリから特定のプロジェクトでタスクを起動する&amp;quot;&amp;gt;別のディレクトリから特定のプロジェクトでタスクを起動する&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;オプション`-p` (ou &amp;lt;code&amp;gt;--project-dir&amp;lt;/code&amp;gt;) Gradleプロジェクトへのパスを指定し、そのプロジェクトでタスクを実行することができます。ただし、現在のディレクトリが異なる場合でもです。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;たとえば、タスクを起動するために`build`プロジェクトが位置する`~/projets/mon-autre-projet`他のディレクトリにいる状態で：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;./gradlew -p ~/projets/mon-autre-projet build&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;これは、中央の場所から複数のプロジェクトにわたるアクションをスクリプト化するのに特に役立ちます。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;参照：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;https://docs.gradle.org/current/userguide/command_line_interface.html#sec:command_line_warnings&amp;quot;&amp;gt;参照&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;https://docs.gradle.org/current/userguide/command_line_interface.html#sec:command_line_options&amp;quot;&amp;gt;参照&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;https://stackoverflow.com/a/36178581/837404&amp;quot;&amp;gt;議論&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;</description>
        </item><item>
            <title>トレーニング - Kotlin: enum, 密封クラス</title>
            <link >https://cheroliv.com/blog/2022/0038_training_kotlin_enum_sealed_class_post.html</link>
            <pubDate>Tue, 17 May 2022 00:00:00 +0000</pubDate>
            <guid isPermaLink="false">blog/2022/0038_training_kotlin_enum_sealed_class_post.html</guid>
            <description>&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;シールクラスは、列挙型（キーワード: enum）ではありません。&amp;lt;br&amp;gt;
Javaから来たあなたは、機能を提供する列挙をオーバーロードしたくなるかもしれません: // Java コード&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-java hljs&amp;quot; data-lang=&amp;quot;java&amp;quot;&amp;gt;enum PizzaOrderStatus {
    ORDER_RECEIVED,
    PIZZA_BEING_MADE,
    OUT_FOR_DELIVERY,
    COMPLETED;
    public PizzaOrderStatus nextStatus() {
        switch (this) {
        case ORDER_RECEIVED: return PIZZA_BEING_MADE;
        case PIZZA_BEING_MADE: return OUT_FOR_DELIVERY;
        case OUT_FOR_DELIVERY: return COMPLETED;
        case COMPLETED:return COMPLETED;
        }
    }
}&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;代わりに、sealed クラスを使用できます：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-kotlin hljs&amp;quot; data-lang=&amp;quot;kotlin&amp;quot;&amp;gt;sealed class PizzaOrderStatus(protected val orderId: Int) {
    abstract fun nextStatus() : PizzaOrderStatus
    class OrderReceived(orderId: Int) : PizzaOrderStatus(orderId) {
        override fun nextStatus(): PizzaOrderStatus {
            return PizzaBeingMade(orderId)
        }
    }
    class PizzaBeingMade(orderId: Int) : PizzaOrderStatus(orderId) {
        override fun nextStatus(): PizzaOrderStatus {
            return OutForDelivery(orderId)
        }
    }
    class OutForDelivery(orderId: Int) : PizzaOrderStatus(orderId) {
        override fun nextStatus(): PizzaOrderStatus {
            return Completed(orderId)
        }
    }
    class Completed(orderId: Int) : PizzaOrderStatus(orderId) {
        override fun nextStatus(): PizzaOrderStatus {
            return this
        }
    }
}&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;このアプローチの利点は、今ではデータを le 送信できることです ステータス:&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-kotlin hljs&amp;quot; data-lang=&amp;quot;kotlin&amp;quot;&amp;gt;var status: PizzaOrderStatus = OrderReceived(123)
while (status !is Completed) {
    status = when (status) {
        is OrderReceived -&amp;amp;gt; status.nextStatus()
        is PizzaBeingMade -&amp;amp;gt; status.nextStatus()
        is OutForDelivery -&amp;amp;gt; status.nextStatus()
        is Completed -&amp;amp;gt; status
    }
}&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;一般的に、sealed クラスは、データを関連付けたい場合に適しています。 状態。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;</description>
        </item><item>
            <title>トレーニング - コトリン</title>
            <link >https://cheroliv.com/blog/2022/0036_training_kotlin_post.html</link>
            <pubDate>Thu, 12 May 2022 00:00:00 +0000</pubDate>
            <guid isPermaLink="false">blog/2022/0036_training_kotlin_post.html</guid>
            <description>&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_マインドマップ&amp;quot;&amp;gt;マインドマップ&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;span class=&amp;quot;image&amp;quot;&amp;gt;&amp;lt;img src=&amp;quot;../../diagram/training_kotlin.png&amp;quot; alt=&amp;quot;training_kotlin&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_関数型プログラミング&amp;quot;&amp;gt;関数型プログラミング&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;演�習は本から取り出されています:&amp;lt;br&amp;gt;
チュートリアルによる Kotlin での関数型プログラミング&amp;lt;br&amp;gt;
Massimo Carli によって書かれました&amp;lt;br&amp;gt;
リポジトリ: &amp;lt;a href=&amp;quot;https://github.com/kodecocodes/fpk-materials&amp;quot; class=&amp;quot;bare&amp;quot;&amp;gt;https://github.com/kodecocodes/fpk-materials&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_構文&amp;quot;&amp;gt;構文&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;sect3&amp;quot;&amp;gt;
&amp;lt;h4 id=&amp;quot;_最初のプログラムテスト&amp;quot;&amp;gt;最初のプログラムテスト&amp;lt;/h4&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;概念: 画面表示, 機能&amp;lt;br&amp;gt;
FirstProgramTest:https://github.com/cheroliv/cheroliv.com/blob/master/codes/src/test/kotlin/programming/FirstProgramTest.kt[ソース]+&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect3&amp;quot;&amp;gt;
&amp;lt;h4 id=&amp;quot;_連結関数テスト&amp;quot;&amp;gt;連結関数テスト&amp;lt;/h4&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;概念: メモリー, 変数, 値, オブジェクト, 関数拡張&amp;lt;br&amp;gt;
ExampleUnitTest: &amp;lt;a href=&amp;quot;https://github.com/cheroliv/cheroliv.com/blob/master/codes/src/test/kotlin/programming/ConcatFunctionTest.kt&amp;quot;&amp;gt;源&amp;lt;/a&amp;gt;+&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect3&amp;quot;&amp;gt;
&amp;lt;h4 id=&amp;quot;_birthdaymessagetestoutput&amp;quot;&amp;gt;BirthdayMessageTestOutput&amp;lt;/h4&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;概念: 集合, ループ&amp;lt;br&amp;gt;
&amp;lt;a href=&amp;quot;https://developer.android.com/codelabs/basic-android-kotlin-training-first-kotlin-program?continue=https%3A%2F%2Fdeveloper.android.com%2Fcourses%2Fpathways%2Fandroid-basics-kotlin-one%23codelab-https%3A%2F%2Fdeveloper.android.com%2Fcodelabs%2Fbasic-android-kotlin-training-first-kotlin-program&amp;quot;&amp;gt;Kotlinの紹介&amp;lt;/a&amp;gt;&amp;lt;br&amp;gt;
�誕生日メッセージテスト出力:https://github.com/cheroliv/cheroliv.com/blob/master/codes/src/test/kotlin/programming/BirthdayMessageTestOutput.kt[ソース]+&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_コトリンコース&amp;quot;&amp;gt;コトリンコース&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;videoblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;iframe src=&amp;quot;https://www.youtube.com/embed/YRjY3jRrQYY?rel=0&amp;quot; frameborder=&amp;quot;0&amp;quot; allowfullscreen&amp;gt;&amp;lt;/iframe&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_javaのコレクションに関するチュートリアル&amp;quot;&amp;gt;Javaのコレクションに関するチュートリアル&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;https://docs.oracle.com/javase/tutorial/collections/index.html&amp;quot; target=&amp;quot;_blank&amp;quot; rel=&amp;quot;noopener&amp;quot;&amp;gt;コレクション&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;コレクションインターフェースの核心&amp;lt;br&amp;gt;
&amp;lt;span class=&amp;quot;image&amp;quot;&amp;gt;&amp;lt;img src=&amp;quot;../../img/0036_training_kotlin_post/colls-coreInterfaces.gif&amp;quot; alt=&amp;quot;Collections&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&amp;lt;br&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_基本的な機能&amp;quot;&amp;gt;基本的な機能&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;sect3&amp;quot;&amp;gt;
&amp;lt;h4 id=&amp;quot;_宣言型_x_命令型アプローチ&amp;quot;&amp;gt;宣言型 X 命令型アプローチ&amp;lt;/h4&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-kotlin hljs&amp;quot; data-lang=&amp;quot;kotlin&amp;quot;&amp;gt;package functional

import kotlin.test.Test
import kotlin.test.assertEquals

class DeclarativeTests {
    val input = listOf(
        &amp;quot;123&amp;quot;, &amp;quot;abc&amp;quot;, &amp;quot;1ds&amp;quot;, &amp;quot;987&amp;quot;, &amp;quot;abdf&amp;quot;, &amp;quot;1d3&amp;quot;, &amp;quot;de1&amp;quot;, &amp;quot;88&amp;quot;, &amp;quot;101&amp;quot;
    )

    fun imperativeSum(list: List&amp;amp;lt;String&amp;amp;gt;): Int {
        var sum = 0
        for (item in list) {
            try {
                sum += item.toInt()
            } catch (_: NumberFormatException) {
            }
        }
        return sum
    }

    @Test
    fun `test imperative approach`() {
        imperativeSum(input).run {
            println(&amp;quot;Sum $this&amp;quot;)
            assertEquals(1299, this)
        }
    }

    fun isValidNumber(s: String) = try {
        s.toInt()
        true
    } catch (_: NumberFormatException) {
        false
    }

    fun declarativeSum(list: List&amp;amp;lt;String&amp;amp;gt;) = list
        .filter(::isValidNumber)
        .map(String::toInt)
        .sum()

    @Test
    fun `test declarative approach`() {
        assertEquals(1299, declarativeSum(input).apply {
            println(&amp;quot;Sum $this&amp;quot;)
        })
    }
}&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect3&amp;quot;&amp;gt;
&amp;lt;h4 id=&amp;quot;_演習_1_1&amp;quot;&amp;gt;演習 1.1&amp;lt;/h4&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;関数 sumInRange を実装し、範囲内の値を加算します&amp;lt;br&amp;gt;
与えられた区間の List&amp;amp;lt;String&amp;amp;gt; 。シグニチャは：&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-kotlin hljs&amp;quot; data-lang=&amp;quot;kotlin&amp;quot;&amp;gt;fun sumInRange(input: List&amp;amp;lt;String&amp;amp;gt;, range: IntRange): Int&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-kotlin hljs&amp;quot; data-lang=&amp;quot;kotlin&amp;quot;&amp;gt;@Test
fun `Exercise 1_1`() {
    assertEquals(4, sumInRange(
        listOf(&amp;quot;1&amp;quot;, &amp;quot;10&amp;quot;, &amp;quot;a&amp;quot;, &amp;quot;7&amp;quot;, &amp;quot;ad2&amp;quot;, &amp;quot;3&amp;quot;),
            1..5
        ).apply { println(&amp;quot;sumInRange 1..5: $this&amp;quot;) }
    )
}&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;お試しください、そしてあなたの答えをそれに合わせて確認してくださいhttps://github.com/cheroliv/cheroliv.com/blob/master/codes/src/test/kotlin/functional/DeclarativeTests.kt[ソリューション, windows=&amp;quot;_blank]。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect3&amp;quot;&amp;gt;
&amp;lt;h4 id=&amp;quot;_高階関数&amp;quot;&amp;gt;高階関数&amp;lt;/h4&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-kotlin hljs&amp;quot; data-lang=&amp;quot;kotlin&amp;quot;&amp;gt;package functional

import java.io.ByteArrayOutputStream
import java.io.PrintStream
import java.lang.System.*
import java.lang.Thread.sleep
import kotlin.math.sign
import kotlin.test.Test
import kotlin.test.assertEquals

class BasicsHOFTests {
    val ONE_SECOND = 1000L

    @Test
    fun `high order function`() {
        //capture de la sortie standard
        val standardOut: PrintStream? = out
        val outputStreamCaptor = ByteArrayOutputStream()
        setOut(PrintStream(outputStreamCaptor))

        3.times { println(&amp;quot;Hello&amp;quot;) }
        assertEquals(
            buildString {
                repeat(3) { append(&amp;quot;Hello\n&amp;quot;) }
                deleteAt(length - 1)
            }, outputStreamCaptor
                .toString()
                .trim()
        )

        //libération de la sortie standard
        setOut(standardOut)
    }

    fun Int.times1(fn: () -&amp;amp;gt; Unit) {
        for (i in 1..this) {
            fn()
        }
    }

    fun Int.times2(fn: () -&amp;amp;gt; Unit) {
        for (i in 1..this) fn()
    }

    fun Int.times3(fn: () -&amp;amp;gt; Unit) =
        (1..this).forEach { fn() }


    fun Int.times4(fn: () -&amp;amp;gt; Unit) =
        repeat((1..this).count()) { fn() }

    fun Int.times(fn: () -&amp;amp;gt; Unit) =
        (1..this).forEach { _ -&amp;amp;gt; fn() }
}&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect3&amp;quot;&amp;gt;
&amp;lt;h4 id=&amp;quot;_演習_1_2&amp;quot;&amp;gt;演習 1.2&amp;lt;/h4&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;chrono を実装し、型の関数を受け取る`() &amp;amp;#8594;`&amp;lt;br&amp;gt;
ユニットを入力として、実行にかかった時間を返します。シグニチャは:+&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-kotlin hljs&amp;quot; data-lang=&amp;quot;kotlin&amp;quot;&amp;gt;fun chrono(fn : () -&amp;amp;gt; Unité) : Long&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-kotlin hljs&amp;quot; data-lang=&amp;quot;kotlin&amp;quot;&amp;gt;@Test
fun `Exercise 1_2`() {
    val waitOneSec = { sleep(ONE_SECOND) }
    chrono(waitOneSec).apply {
        println(&amp;quot;chrono: $this&amp;quot;)
        assertEquals(1, sign)
    }
}&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;試してみて、それに合わせてあなたの答えを確認してhttps://github.com/cheroliv/cheroliv.com/blob/master/codes/src/test/kotlin/functional/BasicsHOFTests.kt[解決策, windows=&amp;quot;_blank].&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect3&amp;quot;&amp;gt;
&amp;lt;h4 id=&amp;quot;_構成&amp;quot;&amp;gt;構成&amp;lt;/h4&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-kotlin hljs&amp;quot; data-lang=&amp;quot;kotlin&amp;quot;&amp;gt;package functional

import kotlin.test.Test
import kotlin.test.assertEquals


fun double(x: Int): Int = 2 * x
fun square(x: Int): Int = x * x
fun squareAndDouble1(x: Int) = double(square(x))

infix fun &amp;amp;lt;A, B, C&amp;amp;gt; ((A) -&amp;amp;gt; B).compose(g: (B) -&amp;amp;gt; C)
        : (A) -&amp;amp;gt; C = { a -&amp;amp;gt; g(this(a)) }

class CompositionTests {
    @Test
    fun composition_impure() {
        assertEquals(200, double(square(10)))
        assertEquals(200, squareAndDouble1(10))
    }

    @Test
    fun composition_pure() {
        val squareAndDouble = ::square compose ::double
        assertEquals(200, squareAndDouble(10))
    }

}&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect3&amp;quot;&amp;gt;
&amp;lt;h4 id=&amp;quot;_純粋関数とテスト容易性&amp;quot;&amp;gt;純粋関数とテスト容易性&amp;lt;/h4&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-kotlin hljs&amp;quot; data-lang=&amp;quot;kotlin&amp;quot;&amp;gt;package functional

import java.io.ByteArrayOutputStream
import java.io.PrintStream
import java.lang.System.out
import java.lang.System.setOut
import kotlin.test.Test
import kotlin.test.assertEquals


var count = 0

//impure car une variable global subit un effet de bord
fun impure(value: Int): Int {
    count++
    return value + count
}

//impure car utilisation de la sortie standard qui fait muter le system
fun addOneAndLog(x: Int): Int {
    val result = x + 1
    println(&amp;quot;New Value is $result&amp;quot;)
    return result
}

//pure
fun addOne(x: Int) = (x + 1).run {
    Pair(this, &amp;quot;New Value is $this&amp;quot;)
}

class PureTests {
    @Test
    fun `impure fonction`() {
        assertEquals(3, impure(2))

        val standardOut = out
        val outputStreamCaptor = ByteArrayOutputStream()
        setOut(PrintStream(outputStreamCaptor))

        addOneAndLog(3)

        assertEquals(
            &amp;quot;New Value is 4&amp;quot;,
            outputStreamCaptor
                .toString()
                .trim()
        )
        setOut(standardOut)
    }

    @Test
    fun `pure fonction`() {
        addOne(3).run {
            assertEquals(4, first)
            assertEquals(&amp;quot;New Value is 4&amp;quot;, second)
        }
    }
}&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect3&amp;quot;&amp;gt;
&amp;lt;h4 id=&amp;quot;_例外処理&amp;quot;&amp;gt;例外処理&amp;lt;/h4&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-kotlin hljs&amp;quot; data-lang=&amp;quot;kotlin&amp;quot;&amp;gt;package functional

import org.junit.jupiter.api.assertThrows
import kotlin.Result.Companion.failure
import kotlin.Result.Companion.success
import kotlin.test.Test
import kotlin.test.assertEquals

//NumberFormatException est un effet de bord qui rend la fonction impure
fun strToInt(str: String) = str.toInt()

//pure
fun strToIntOrNull(str: String) = try {
    str.toInt()
} catch (nfe: NumberFormatException) {
    null
}

//pure avec gestion de l&amp;#39;exception plus élégante
fun strToIntResult(str: String): Result&amp;amp;lt;Int&amp;amp;gt; =
    try {
        success(str.toInt())
    } catch (nfe: NumberFormatException) {
        failure(nfe)
    }

class ExceptionHandlingTests {
    @Test
    fun impure() {
        assertThrows&amp;amp;lt;NumberFormatException&amp;amp;gt; { strToInt(&amp;quot;foo&amp;quot;) }
        assertEquals(1, strToInt(&amp;quot;1&amp;quot;))
    }

    @Test
    fun pure() {
        assertEquals(null, strToIntOrNull(&amp;quot;foo&amp;quot;))
        assertEquals(1, strToIntOrNull(&amp;quot;1&amp;quot;))
    }

    @Test
    fun `pure avec result`() {
        assertEquals(1, strToIntResult(&amp;quot;1&amp;quot;).getOrNull())
        assertEquals(
            &amp;quot;For input string: \&amp;quot;foo\&amp;quot;&amp;quot;,
            strToIntResult(&amp;quot;foo&amp;quot;)
                .exceptionOrNull()
                ?.message
        )
    }
}&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_重要なポイント&amp;quot;&amp;gt;重要なポイント&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;オブジェクト指向プログラミングは、オブジェクトを使ってプログラミングすることを意味します。&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;関数型プログラミングは、関数を使ってプログラムを書くことを意味します。 問題をいくつかのサブ問題に分解し、それらをモデル化します 機能。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;高階関数は他の関数を入力として受け取るか、他のを返します。&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;返り値として機能します。 カテゴリ理論は合成の理論であり、あなたはそれを理解するために使います。 作業プログラムで関数をどのように組み立てますか。 純粋な関数の出力値は、その入力パラメータにのみ依存し、それは 副作用はありません。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;副作用は、関数が外部世界に行う何かです。&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;標準出力にログを出力するか、グローバル変数の値を変更する可能性があります。 関数型プログラミングは純粋な関数に対して機能します。しかし、それはまたを提供します 不純な関数を純粋な関数に変換するツール 副作用を移動させることで、不純な関数を純粋にすることができます 戻り値の一部。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;関数型プログラミングは、組み合わせに関するものです。&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;エラー処理は副作用の典型的なケースであり、Kotlinはツールを提供します それらを機能的に管理するために。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_java_8を深く学ぶ_ラムダ式と関数型インターフェース&amp;quot;&amp;gt;Java 8を深く学ぶ: ラムダ式と関数型インターフェース&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;videoblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;iframe src=&amp;quot;https://www.youtube.com/embed/20waNRw6wMA?rel=0&amp;amp;amp;list=PLzzeuFUy_Cng0wZhqbnkvWAW0d2fdVfyQ&amp;quot; frameborder=&amp;quot;0&amp;quot; allowfullscreen&amp;gt;&amp;lt;/iframe&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_圏論&amp;quot;&amp;gt;�圏論&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;数学的カテゴリー理論:&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;videoblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;iframe src=&amp;quot;https://www.youtube.com/embed/LVHoROSF3KA?rel=0&amp;quot; frameborder=&amp;quot;0&amp;quot; allowfullscreen&amp;gt;&amp;lt;/iframe&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_関数の基礎&amp;quot;&amp;gt;関数の基礎&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;sect3&amp;quot;&amp;gt;
&amp;lt;h4 id=&amp;quot;_問題_2_1&amp;quot;&amp;gt;問題 2.1&amp;lt;/h4&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;一意な値にマッピングする関数の例を書くことができますか？&amp;lt;br&amp;gt;
ドメインが範囲内で一意でない値を持つ場合、例えば以下の図の f(b) と f(c) のように？&amp;lt;br&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;やってみて、その後、チャレンジプロジェクトの解答を確認して、自分がどうだったかを見てみよう。&amp;lt;br&amp;gt;
アドバイスと説明は、リンクに従って先へ進むと見つかります。 &amp;lt;a href=&amp;quot;https://github.com/cheroliv/cheroliv.com/blob/master/codes/src/test/kotlin/functional/BasicsHOFTests.kt&amp;quot;&amp;gt;解決策&amp;lt;/a&amp;gt;.&amp;lt;br&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect3&amp;quot;&amp;gt;
&amp;lt;h4 id=&amp;quot;_演習_2_2&amp;quot;&amp;gt;演習 2.2&amp;lt;/h4&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;２倍の関数の逆関数を書くことができますか？&amp;lt;br&amp;gt;
逆関数の定義域と値域は何ですか？&amp;lt;br&amp;gt;
解答については、チャレンジプロジェクトと付録Bを参照してください。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-kotlin hljs&amp;quot; data-lang=&amp;quot;kotlin&amp;quot;&amp;gt;fun chrono(fn : () -&amp;amp;gt; Unité) : Long&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-kotlin hljs&amp;quot; data-lang=&amp;quot;kotlin&amp;quot;&amp;gt;@Test
fun `Exercise 1_2`() {
    val waitOneSec = { sleep(ONE_SECOND) }
    chrono(waitOneSec).apply {
        println(&amp;quot;chrono: $this&amp;quot;)
        assertEquals(1, sign)
    }
}&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;試してみて、そしてそれによってあなたの答えを確認してhttps://github.com/cheroliv/cheroliv.com/blob/master/codes/src/test/kotlin/functional/BasicsHOFTests.kt[解決策, windows=&amp;quot;_blank]。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;</description>
        </item><item>
            <title>デザインシステムのメモ</title>
            <link >https://cheroliv.com/blog/2022/0031_memo_design_system_post.html</link>
            <pubDate>Sun, 9 Jan 2022 00:00:00 +0000</pubDate>
            <guid isPermaLink="false">blog/2022/0031_memo_design_system_post.html</guid>
            <description>&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_ツール&amp;quot;&amp;gt;ツール&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;dlist&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;イラスト&amp;lt;/strong&amp;gt;&amp;lt;/div&amp;gt;
&amp;lt;dl&amp;gt;
&amp;lt;dt class=&amp;quot;hdlist1&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;https://undraw.co/&amp;quot;&amp;gt;undraw.co&amp;lt;/a&amp;gt;&amp;lt;/dt&amp;gt;
&amp;lt;dd&amp;gt;
&amp;lt;p&amp;gt;オープンソースのイラストは、想像できるすべてのアイデアに使えます。&amp;lt;/p&amp;gt;
&amp;lt;/dd&amp;gt;
&amp;lt;dt class=&amp;quot;hdlist1&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;https://absurd.design/&amp;quot;&amp;gt;absurd.design&amp;lt;/a&amp;gt;&amp;lt;/dt&amp;gt;
&amp;lt;dd&amp;gt;
&amp;lt;p&amp;gt;意味があるばかげたイラスト&amp;lt;/p&amp;gt;
&amp;lt;/dd&amp;gt;
&amp;lt;dt class=&amp;quot;hdlist1&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;https://drawkit.com/&amp;quot;&amp;gt;drawkit.com&amp;lt;/a&amp;gt;&amp;lt;/dt&amp;gt;
&amp;lt;dd&amp;gt;
&amp;lt;p&amp;gt;素晴らしい無料イラストレーション。毎週のアップデート。&amp;lt;/p&amp;gt;
&amp;lt;/dd&amp;gt;
&amp;lt;dt class=&amp;quot;hdlist1&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;https://icons8.com/&amp;quot;&amp;gt;icons8.com&amp;lt;/a&amp;gt;&amp;lt;/dt&amp;gt;
&amp;lt;dd&amp;gt;
&amp;lt;p&amp;gt;アイコン、イラスト、写真、音楽、およびデザインツール。&amp;lt;/p&amp;gt;
&amp;lt;/dd&amp;gt;
&amp;lt;dt class=&amp;quot;hdlist1&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;https://blush.design/&amp;quot;&amp;gt;チーク.デザイン&amp;lt;/a&amp;gt;&amp;lt;/dt&amp;gt;
&amp;lt;dd&amp;gt;
&amp;lt;p&amp;gt;アイコン、イラスト、写真、音楽、デザインツール&amp;lt;/p&amp;gt;
&amp;lt;/dd&amp;gt;
&amp;lt;dt class=&amp;quot;hdlist1&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;https://www.humaaans.com/&amp;quot;&amp;gt;humaaans.com&amp;lt;/a&amp;gt;&amp;lt;/dt&amp;gt;
&amp;lt;dd&amp;gt;
&amp;lt;p&amp;gt;人物のイラストレーションをデザインライブラリとミックス＆マッチしてください。&amp;lt;/p&amp;gt;
&amp;lt;/dd&amp;gt;
&amp;lt;/dl&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;dlist&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;色&amp;lt;/strong&amp;gt;&amp;lt;/div&amp;gt;
&amp;lt;dl&amp;gt;
&amp;lt;dt class=&amp;quot;hdlist1&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;https://coolors.co/&amp;quot;&amp;gt;coolors.co&amp;lt;/a&amp;gt;&amp;lt;/dt&amp;gt;
&amp;lt;dd&amp;gt;
&amp;lt;p&amp;gt;超高速カラースキームジェネレーター！&amp;lt;/p&amp;gt;
&amp;lt;/dd&amp;gt;
&amp;lt;/dl&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;dlist&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;傾向&amp;lt;/strong&amp;gt;&amp;lt;/div&amp;gt;
&amp;lt;dl&amp;gt;
&amp;lt;dt class=&amp;quot;hdlist1&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;https://fr.pinterest.com&amp;quot;&amp;gt;ピンタレスト&amp;lt;/a&amp;gt;&amp;lt;/dt&amp;gt;
&amp;lt;dd&amp;gt;
&amp;lt;p&amp;gt;視覚的なアイデアの発見：画像、動画、テーマ別コレクション。&amp;lt;/p&amp;gt;
&amp;lt;/dd&amp;gt;
&amp;lt;dt class=&amp;quot;hdlist1&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;https://dribbble.com&amp;quot;&amp;gt;ドリブル&amp;lt;/a&amp;gt;&amp;lt;/dt&amp;gt;
&amp;lt;dd&amp;gt;
&amp;lt;p&amp;gt;デザイナーが作品を共有し、交流するプラットフォーム&amp;lt;/p&amp;gt;
&amp;lt;/dd&amp;gt;
&amp;lt;/dl&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;dlist&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;UX/UI と Design Systems&amp;lt;/strong&amp;gt;&amp;lt;/div&amp;gt;
&amp;lt;dl&amp;gt;
&amp;lt;dt class=&amp;quot;hdlist1&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;https://material.io/&amp;quot;&amp;gt;Google マテリアルデザイン&amp;lt;/a&amp;gt;&amp;lt;/dt&amp;gt;
&amp;lt;dd&amp;gt;
&amp;lt;p&amp;gt;Googleの統一および適応可能なユーザーインターフェース向けデザインシステム&amp;lt;/p&amp;gt;
&amp;lt;/dd&amp;gt;
&amp;lt;dt class=&amp;quot;hdlist1&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;https://developer.apple.com/design/human-interface-guidelines/&amp;quot;&amp;gt;Apple ヒューマン インターフェイス ガイドライン&amp;lt;/a&amp;gt;&amp;lt;/dt&amp;gt;
&amp;lt;dd&amp;gt;
&amp;lt;p&amp;gt;AppleのiOSおよびmacOS向け直感的なアプリケーション設計の推奨事項。&amp;lt;/p&amp;gt;
&amp;lt;/dd&amp;gt;
&amp;lt;dt class=&amp;quot;hdlist1&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;https://www.uxpin.com/&amp;quot;&amp;gt;UXPin&amp;lt;/a&amp;gt;&amp;lt;/dt&amp;gt;
&amp;lt;dd&amp;gt;
&amp;lt;p&amp;gt;プロトタイプとデザインシステムを作成するためのデザインとコラボレーションのプラットフォーム。&amp;lt;/p&amp;gt;
&amp;lt;/dd&amp;gt;
&amp;lt;dt class=&amp;quot;hdlist1&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;https://www.frontify.com/&amp;quot;&amp;gt;フロンティファイ&amp;lt;/a&amp;gt;&amp;lt;/dt&amp;gt;
&amp;lt;dd&amp;gt;
&amp;lt;p&amp;gt;ブランドおよびデザインシステムの管理プラットフォームで、一貫性を確保します。&amp;lt;/p&amp;gt;
&amp;lt;/dd&amp;gt;
&amp;lt;dt class=&amp;quot;hdlist1&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;https://designsystemsrepo.com/design-systems/&amp;quot;&amp;gt;デザインシステム リポジトリ&amp;lt;/a&amp;gt;&amp;lt;/dt&amp;gt;
&amp;lt;dd&amp;gt;
&amp;lt;p&amp;gt;インスピレーションのためのリソースとデザインシステムの例のコレクション。&amp;lt;/p&amp;gt;
&amp;lt;/dd&amp;gt;
&amp;lt;/dl&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;dlist&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;*フロントエンド開発&amp;lt;/div&amp;gt;
&amp;lt;dl&amp;gt;
&amp;lt;dt class=&amp;quot;hdlist1&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;https://htmlcheatsheet.com&amp;quot; target=&amp;quot;&amp;quot;_blank&amp;quot;&amp;gt;htmlcheatsheet.com&amp;lt;/a&amp;gt;&amp;lt;/dt&amp;gt;
&amp;lt;dd&amp;gt;
&amp;lt;p&amp;gt;HTMLチートシート&amp;lt;/p&amp;gt;
&amp;lt;/dd&amp;gt;
&amp;lt;dt class=&amp;quot;hdlist1&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;https://fontawesome.com&amp;quot; target=&amp;quot;&amp;quot;_blank&amp;quot;&amp;gt;fontawesome.com&amp;lt;/a&amp;gt;&amp;lt;/dt&amp;gt;
&amp;lt;dd&amp;gt;
&amp;lt;p&amp;gt;アイコンライブラリ&amp;lt;/p&amp;gt;
&amp;lt;/dd&amp;gt;
&amp;lt;dt class=&amp;quot;hdlist1&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;https://www.toptal.com/designers/htmlarrows/symbols/&amp;quot;&amp;gt;toptal.com/designers/htmlarrows/symbols&amp;lt;/a&amp;gt;&amp;lt;/dt&amp;gt;
&amp;lt;dd&amp;gt;
&amp;lt;p&amp;gt;HTMLのネイティブアイコン&amp;lt;/p&amp;gt;
&amp;lt;/dd&amp;gt;
&amp;lt;dt class=&amp;quot;hdlist1&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;https://css-tricks.com/&amp;quot;&amp;gt;CSS-Tricks&amp;lt;/a&amp;gt;&amp;lt;/dt&amp;gt;
&amp;lt;dd&amp;gt;
&amp;lt;p&amp;gt;CSSに欠かせない、最新のフロントエンドの記事、チュートリアル、コツ&amp;lt;/p&amp;gt;
&amp;lt;/dd&amp;gt;
&amp;lt;dt class=&amp;quot;hdlist1&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;https://www.frontendmentor.io/&amp;quot;&amp;gt;フロントエンド メンター&amp;lt;/a&amp;gt;&amp;lt;/dt&amp;gt;
&amp;lt;dd&amp;gt;
&amp;lt;p&amp;gt;実プロジェクトに基づくフロントエンドコードの課題でスキルを向上させましょう。&amp;lt;/p&amp;gt;
&amp;lt;/dd&amp;gt;
&amp;lt;dt class=&amp;quot;hdlist1&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;https://dev.to/&amp;quot;&amp;gt;Dev.to&amp;lt;/a&amp;gt;&amp;lt;/dt&amp;gt;
&amp;lt;dd&amp;gt;
&amp;lt;p&amp;gt;開発者コミュニティで記事、チュートリアル、プロジェクトを共有&amp;lt;/p&amp;gt;
&amp;lt;/dd&amp;gt;
&amp;lt;dt class=&amp;quot;hdlist1&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;https://codepen.io/&amp;quot;&amp;gt;CodePen&amp;lt;/a&amp;gt;&amp;lt;/dt&amp;gt;
&amp;lt;dd&amp;gt;
&amp;lt;p&amp;gt;オンラインのコードエディターと、コードスニペットやデモを共有するコミュニティ。&amp;lt;/p&amp;gt;
&amp;lt;/dd&amp;gt;
&amp;lt;/dl&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;dlist&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;AIを活用したフロントエンド開発&amp;lt;/strong&amp;gt;&amp;lt;/div&amp;gt;
&amp;lt;dl&amp;gt;
&amp;lt;dt class=&amp;quot;hdlist1&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;https://v0.dev/&amp;quot;&amp;gt;v0.dev&amp;lt;/a&amp;gt;&amp;lt;/dt&amp;gt;
&amp;lt;dd&amp;gt;
&amp;lt;p&amp;gt;v0 は自然言語の説明をコードとユーザーインターフェースに変換します。&amp;lt;/p&amp;gt;
&amp;lt;/dd&amp;gt;
&amp;lt;dt class=&amp;quot;hdlist1&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;https://uizard.io/&amp;quot;&amp;gt;ウィザード&amp;lt;/a&amp;gt;&amp;lt;/dt&amp;gt;
&amp;lt;dd&amp;gt;
&amp;lt;p&amp;gt;Uizard は、モックアップ（画像、スケッチ）を HTML、CSS、React のコードに変換することに注力しています。&amp;lt;/p&amp;gt;
&amp;lt;/dd&amp;gt;
&amp;lt;dt class=&amp;quot;hdlist1&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;https://www.usegalileo.ai/explore&amp;quot;&amp;gt;usegalileo.ai&amp;lt;/a&amp;gt;&amp;lt;/dt&amp;gt;
&amp;lt;dd&amp;gt;
&amp;lt;p&amp;gt;Galileo AI は自然言語で作りたいインターフェイスを説明することができ、AI が編集可能な Figma デザインを生成します。&amp;lt;/p&amp;gt;
&amp;lt;/dd&amp;gt;
&amp;lt;dt class=&amp;quot;hdlist1&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;https://play.teleporthq.io/&amp;quot;&amp;gt;TeleportHQ&amp;lt;/a&amp;gt;&amp;lt;/dt&amp;gt;
&amp;lt;dd&amp;gt;
&amp;lt;p&amp;gt;TeleportHQは、AIを活用して視覚的にウェブサイトを構築・デプロイするのを支援するローコードフロントエンド開発プラットフォームです。&amp;lt;/p&amp;gt;
&amp;lt;/dd&amp;gt;
&amp;lt;/dl&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;</description>
        </item><item>
            <title>Kubernetes、Microk8s、Docker: 初めての手順</title>
            <link >https://cheroliv.com/blog/2020/0029_kubernetes_microk8s_docker_premiers_pas_post.html</link>
            <pubDate>Tue, 3 Nov 2020 00:00:00 +0000</pubDate>
            <guid isPermaLink="false">blog/2020/0029_kubernetes_microk8s_docker_premiers_pas_post.html</guid>
            <description>&amp;lt;div id=&amp;quot;preamble&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;https://microk8s.io/docs/&amp;quot;&amp;gt;MicroK8s の公式ドキュメント&amp;lt;/a&amp;gt;+&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect3&amp;quot;&amp;gt;
&amp;lt;h4 id=&amp;quot;_microk8sパッケージのインストール&amp;quot;&amp;gt;microk8sパッケージのインストール:&amp;lt;/h4&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;</description>
        </item><item>
            <title>Gradle: Gradleタスクから外部プロセスを実行する</title>
            <link >https://cheroliv.com/blog/2020/0028_gradle_executer_un_processus_externe_depuis_une_tache_gradle_post.html</link>
            <pubDate>Mon, 28 Sep 2020 00:00:00 +0000</pubDate>
            <guid isPermaLink="false">blog/2020/0028_gradle_executer_un_processus_externe_depuis_une_tache_gradle_post.html</guid>
            <description>&amp;lt;div class=&amp;quot;sect3&amp;quot;&amp;gt;
&amp;lt;h4 id=&amp;quot;_gradle_kotlin_dsl&amp;quot;&amp;gt;Gradle-Kotlin-DSL:&amp;lt;/h4&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-kotlin hljs&amp;quot; data-lang=&amp;quot;kotlin&amp;quot;&amp;gt;&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;</description>
        </item><item>
            <title>Kotlin: NotImplementedException, NotImplementedError</title>
            <link >https://cheroliv.com/blog/2020/0027_kotlin_not_implemented_exception_not_implemented_error_post.html</link>
            <pubDate>Sun, 27 Sep 2020 00:00:00 +0000</pubDate>
            <guid isPermaLink="false">blog/2020/0027_kotlin_not_implemented_exception_not_implemented_error_post.html</guid>
            <description>&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;NotImplementedException NotImplementedError、テストでの有用性で、どこまで進んでいるかを知ることができ、失敗の原因も分かります。&amp;lt;br&amp;gt;
まだ実装されておらず、正しい例外をスローできます。&amp;lt;br&amp;gt;
Il y a :&amp;lt;br&amp;gt;
&amp;lt;a href=&amp;quot;http://commons.apache.org/proper/commons-lang/javadocs/api-release/org/apache/commons/lang3/NotImplementedException.html&amp;quot;&amp;gt;org.apache.commons.lang3.NotImplementedException&amp;lt;/a&amp;gt;&amp;lt;br&amp;gt;
&amp;lt;a href=&amp;quot;https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-not-implemented-error/&amp;quot;&amp;gt;kotlin.NotImplementedError&amp;lt;/a&amp;gt;+&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;</description>
        </item><item>
            <title>展開</title>
            <link >https://cheroliv.com/blog/2020/0026_untar_post.html</link>
            <pubDate>Sat, 26 Sep 2020 00:00:00 +0000</pubDate>
            <guid isPermaLink="false">blog/2020/0026_untar_post.html</guid>
            <description>&amp;lt;div class=&amp;quot;sect3&amp;quot;&amp;gt;
&amp;lt;h4 id=&amp;quot;_リンク_interserver_net&amp;quot;&amp;gt;リンク: &amp;lt;a href=&amp;quot;https://www.interserver.net/tips/kb/extract-tar-gz-files-using-linux-command-line/&amp;quot;&amp;gt;interserver.net&amp;lt;/a&amp;gt;&amp;lt;/h4&amp;gt;

&amp;lt;/div&amp;gt;</description>
        </item><item>
            <title>Gradle: テストが最新でもテストを再実行する</title>
            <link >https://cheroliv.com/blog/2020/0025_gradle_rejouer_les_tests_meme_lorsque_les_tests_sont_UP-TO-DATE_post.html</link>
            <pubDate>Fri, 25 Sep 2020 00:00:00 +0000</pubDate>
            <guid isPermaLink="false">blog/2020/0025_gradle_rejouer_les_tests_meme_lorsque_les_tests_sont_UP-TO-DATE_post.html</guid>
            <description></description>
        </item><item>
            <title>Docker、アプリケーションをインストールせず、代わりにプルします</title>
            <link >https://cheroliv.com/blog/2020/0024_docker_n_installe_pas_l_application_mais_tire_la_plutot_post.html</link>
            <pubDate>Thu, 24 Sep 2020 00:00:00 +0000</pubDate>
            <guid isPermaLink="false">blog/2020/0024_docker_n_installe_pas_l_application_mais_tire_la_plutot_post.html</guid>
            <description>&amp;lt;div class=&amp;quot;sect3&amp;quot;&amp;gt;
&amp;lt;h4 id=&amp;quot;_hackernoon_com&amp;quot;&amp;gt;&amp;lt;a href=&amp;quot;https://hackernoon.com/dont-install-postgres-docker-pull-postgres-bee20e200198&amp;quot;&amp;gt;hackernoon.com&amp;lt;/a&amp;gt;&amp;lt;/h4&amp;gt;

&amp;lt;/div&amp;gt;</description>
        </item><item>
            <title>Gherkin（フランス語）:</title>
            <link >https://cheroliv.com/blog/2020/0023_gherkin_en_francais_post.html</link>
            <pubDate>Wed, 23 Sep 2020 00:00:00 +0000</pubDate>
            <guid isPermaLink="false">blog/2020/0023_gherkin_en_francais_post.html</guid>
            <description></description>
        </item><item>
            <title>Gradle cli: パラメータをオーバーライドする</title>
            <link >https://cheroliv.com/blog/2020/0022_gradle_cli_surcharger_un_parametre_post.html</link>
            <pubDate>Tue, 22 Sep 2020 00:00:00 +0000</pubDate>
            <guid isPermaLink="false">blog/2020/0022_gradle_cli_surcharger_un_parametre_post.html</guid>
            <description>&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-none hljs&amp;quot;&amp;gt;----
----
$ ./gradlew -Pparam_component=CUSTOM
----
----&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;</description>
        </item><item>
            <title>メモ git</title>
            <link >https://cheroliv.com/blog/2020/0021_memo_git_post.html</link>
            <pubDate>Mon, 21 Sep 2020 00:00:00 +0000</pubDate>
            <guid isPermaLink="false">blog/2020/0021_memo_git_post.html</guid>
            <description>&amp;lt;div class=&amp;quot;sect3&amp;quot;&amp;gt;
&amp;lt;h4 id=&amp;quot;_出典&amp;quot;&amp;gt;出典:&amp;lt;/h4&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;*https://xenovation.com/blog/source-control-management/git/how-to-change-remote-git-repository[ゼノベーション] *https://intellipaat.com/community/3102/git-show-remote-url-how-can-i-determine-the-url-that-a-local-git-repository-was-originally-cloned-from[インテリパート]&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect3&amp;quot;&amp;gt;
&amp;lt;h4 id=&amp;quot;_git_のリモートリポジトリを変更する&amp;quot;&amp;gt;git のリモートリポジトリを変更する&amp;lt;/h4&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;現在のリモートリポジトリのURLを表示:&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;</description>
        </item><item>
            <title>URL から吸い取る</title>
            <link >https://cheroliv.com/blog/2020/0021_aspirer_depuis_une_URL_post.html</link>
            <pubDate>Sun, 20 Sep 2020 00:00:00 +0000</pubDate>
            <guid isPermaLink="false">blog/2020/0021_aspirer_depuis_une_URL_post.html</guid>
            <description>&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-none hljs&amp;quot;&amp;gt;----
----
$ wget -r -k -np http://site.com/docs/manual/
----

ターゲットフォルダーを設定するには、-P引数を追加し、パスを指定してください。
----&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;</description>
        </item><item>
            <title>ブート可能なディスクを作成</title>
            <link >https://cheroliv.com/blog/2020/0020_creer_un_disk_bootable_post.html</link>
            <pubDate>Sat, 19 Sep 2020 00:00:00 +0000</pubDate>
            <guid isPermaLink="false">blog/2020/0020_creer_un_disk_bootable_post.html</guid>
            <description>&amp;lt;div class=&amp;quot;sect3&amp;quot;&amp;gt;
&amp;lt;h4 id=&amp;quot;_リンク_etcher&amp;quot;&amp;gt;リンク: &amp;lt;a href=&amp;quot;https://www.balena.io/etcher/&amp;quot;&amp;gt;etcher&amp;lt;/a&amp;gt;&amp;lt;/h4&amp;gt;

&amp;lt;/div&amp;gt;</description>
        </item><item>
            <title>CLI でターゲットフォルダーに解凍する</title>
            <link >https://cheroliv.com/blog/2020/0019_dezipper_en_CLI_dans_un_dossier_cible_post.html</link>
            <pubDate>Fri, 18 Sep 2020 00:00:00 +0000</pubDate>
            <guid isPermaLink="false">blog/2020/0019_dezipper_en_CLI_dans_un_dossier_cible_post.html</guid>
            <description>&amp;lt;div class=&amp;quot;sect3&amp;quot;&amp;gt;
&amp;lt;h4 id=&amp;quot;_リンク_askubuntu&amp;quot;&amp;gt;リンク: &amp;lt;a href=&amp;quot;https://askubuntu.com/questions/86849/how-to-unzip-a-zip-file-from-the-terminal&amp;quot;&amp;gt;askubuntu&amp;lt;/a&amp;gt;&amp;lt;/h4&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;特定の出力フォルダーに抽出したい場合は、以下を使用できます : &amp;lt;code&amp;gt;` $ unzip ファイル.zip -d 出力先フォルダー &amp;lt;/code&amp;gt;` ソース ディレクトリと宛先ディレクトリが同じ場合、次のようにするだけです： &amp;lt;code&amp;gt;` $ unzip file.zip &amp;lt;/code&amp;gt;`&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;</description>
        </item><item>
            <title>ディレクトリのリストにファイルサイズの合計を表示</title>
            <link >https://cheroliv.com/blog/2020/0018_Afficher_la_somme_des_tailles_de_fichier_dans_la_liste_des_r%C3%A9pertoires_post.html</link>
            <pubDate>Thu, 17 Sep 2020 00:00:00 +0000</pubDate>
            <guid isPermaLink="false">blog/2020/0018_Afficher_la_somme_des_tailles_de_fichier_dans_la_liste_des_r%C3%A9pertoires_post.html</guid>
            <description>&amp;lt;div class=&amp;quot;sect3&amp;quot;&amp;gt;
&amp;lt;h4 id=&amp;quot;_リンク_stackexchange&amp;quot;&amp;gt;リンク: &amp;lt;a href=&amp;quot;https://unix.stackexchange.com/questions/72661/show-sum-of-file-sizes-in-directory-listing&amp;quot;&amp;gt;stackexchange&amp;lt;/a&amp;gt;&amp;lt;/h4&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-none hljs&amp;quot;&amp;gt;----
----
$ du -ach --exclude &amp;quot;./.*&amp;quot; /home/troll/
----
----&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;</description>
        </item><item>
            <title>GitHubのブランチを削除する</title>
            <link >https://cheroliv.com/blog/2020/0017_detruire_une_branch_sur_github_post.html</link>
            <pubDate>Wed, 16 Sep 2020 00:00:00 +0000</pubDate>
            <guid isPermaLink="false">blog/2020/0017_detruire_une_branch_sur_github_post.html</guid>
            <description>&amp;lt;div class=&amp;quot;sect3&amp;quot;&amp;gt;
&amp;lt;h4 id=&amp;quot;_githubのブランチを削除する&amp;quot;&amp;gt;GitHubのブランチを削除する&amp;lt;/h4&amp;gt;

&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect3&amp;quot;&amp;gt;
&amp;lt;h4 id=&amp;quot;_リンク_gist&amp;quot;&amp;gt;リンク: &amp;lt;a href=&amp;quot;https://gist.github.com/cheroliv/921a13ed23ae6d4d66af8d43dd536987&amp;quot;&amp;gt;gist&amp;lt;/a&amp;gt;&amp;lt;/h4&amp;gt;

&amp;lt;/div&amp;gt;</description>
        </item><item>
            <title>Asciidoc/Markdown メモ</title>
            <link >https://cheroliv.com/blog/2020/0016_asciidoc_markdown_memo_post.html</link>
            <pubDate>Tue, 15 Sep 2020 00:00:00 +0000</pubDate>
            <guid isPermaLink="false">blog/2020/0016_asciidoc_markdown_memo_post.html</guid>
            <description>&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;なぜAsciiDocまたはMarkdownを使うのですか？ ここで、私はasciidocへと傾いています。なぜなら、私はすでにいくつかのチケットをasciidocで書いているからです。&amp;lt;br&amp;gt;
Asciidocはマークアップ言語で、人間にとって読みやすいテキストを保ちながら、レイアウトを提供することでコンテンツを作成できます。&amp;lt;br&amp;gt;
これは、追加のソフトウェアを必要とせず、シンプルなコンテンツのテキスト処理を標準化する方法です。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;ulist&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;title&amp;quot;&amp;gt;` &amp;lt;code&amp;gt;リンク&amp;lt;/code&amp;gt; :&amp;lt;/div&amp;gt;
&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;https://blog.oxiane.com/2018/06/13/asciidoc-documentation-as-code/&amp;quot;&amp;gt;@jmdoudoux、blog.oxiane.com上、window=&amp;quot;_blank&amp;lt;/a&amp;gt; [asciidoc]&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;li&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;https://powerman.name/doc/asciidoc&amp;quot; target=&amp;quot;&amp;quot;_blank&amp;quot;&amp;gt;powerman.name&amp;lt;/a&amp;gt;[アスキードック]&amp;lt;/p&amp;gt;
&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;</description>
        </item><item>
            <title>Debian: コマンドラインで .deb ファイルをインストールする</title>
            <link >https://cheroliv.com/blog/2019/0013_how-to-install-a-deb-file_post.html</link>
            <pubDate>Mon, 19 Aug 2019 00:00:00 +0000</pubDate>
            <guid isPermaLink="false">blog/2019/0013_how-to-install-a-deb-file_post.html</guid>
            <description>&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;Debian パッケージを .deb ファイルからコマンドラインでインストールするには。&amp;lt;br&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;$ sudo dpkg -i /chemin/du/fichier/deb/&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;ここで見るためのhttps://unix.stackexchange.com/questions/159094/how-to-install-a-deb-file-by-dpkg-i-or-by-apt[参照]+&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;</description>
        </item><item>
            <title>Gradle: IDE で表示されるリソースフォルダー</title>
            <link >https://cheroliv.com/blog/2019/0011_gradle_configuration_ide_jbake_content_post.html</link>
            <pubDate>Fri, 16 Aug 2019 00:00:00 +0000</pubDate>
            <guid isPermaLink="false">blog/2019/0011_gradle_configuration_ide_jbake_content_post.html</guid>
            <description>&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;Gradle ビルドマネージャーが管理するアプリケーションプロジェクトでは&amp;lt;br&amp;gt;
すべてのフォルダーを可視にしていると、より快適です。&amp;lt;br&amp;gt;
アプリケーションの開発に参加している&amp;lt;br&amp;gt;
リソースフォルダーではないような&amp;lt;br&amp;gt;
慣例により、道筋において&amp;lt;br&amp;gt;
例えば、src/jbake ディレクトリが欲しい,&amp;lt;br&amp;gt;
「resource folder」として可視である&amp;lt;br&amp;gt;
プロジェクトの設定に入ることで、それを行うことができます、&amp;lt;br&amp;gt;
IDE のウィザードで。 ただしこのオプションは次のリロード時に保存されません&amp;lt;br&amp;gt;
IDEのGradleプロジェクト。この設定を永続的に適用するために&amp;lt;br&amp;gt;
ソリューションは、ソースパスの設定をオーバーライドすることです&amp;lt;br&amp;gt;
build.gradle 構成ファイルの 18 行目、19 行目、20 行目、21 行目のように :&amp;lt;br&amp;gt;
build.gradle&amp;lt;br&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-groovy hljs&amp;quot; data-lang=&amp;quot;groovy&amp;quot;&amp;gt;plugins {
    id &amp;quot;java&amp;quot;
    id &amp;quot;groovy&amp;quot;
    id &amp;quot;org.jbake.site&amp;quot; version &amp;quot;5.0.0&amp;quot;
    id &amp;quot;org.ajoberstar.git-publish&amp;quot; version &amp;quot;2.1.1&amp;quot;
}
repositories {
    mavenCentral()
    jcenter()
}
group project_group
version project_version
sourceSets {
    main {
        java { srcDirs = [] }
        groovy { srcDirs =[&amp;quot;src/main/java&amp;quot;, &amp;quot;src/main/groovy&amp;quot;] }
        resources {
            srcDirs =[
                    &amp;quot;src/main/resources&amp;quot;,
                    &amp;quot;src/jbake&amp;quot;//in order to get site src content in the IDE
            ]
        }
    }
    test {
        java { srcDirs = [] }
        groovy { srcDirs =[&amp;quot;src/test/java&amp;quot;, &amp;quot;src/test/groovy&amp;quot;] }
    }
}
test {
    useJUnitPlatform()
}
configurations {
    ivy
}
dependencies {
    ivy &amp;quot;org.apache.ivy:ivy:$ivy_version&amp;quot;
    implementation &amp;quot;org.codehaus.groovy:groovy-all:$groovy_version&amp;quot;
    implementation &amp;quot;org.asciidoctor:asciidoctor-java-integration:$asciidoctor_java_integration_version&amp;quot;
    implementation &amp;quot;org.freemarker:freemarker:$freemarker_version&amp;quot;
    testImplementation &amp;quot;org.junit.jupiter:junit-jupiter-api:$junit5_version&amp;quot;
    testRuntimeOnly &amp;quot;org.junit.jupiter:junit-jupiter-engine:$junit5_version&amp;quot;
}
gitPublish {
    repoUri = github_pages_blog_repository
    branch = git_branch
    contents {
        from(file(jbake_content_from)) {
            into jbake_content_to
        }
    }
}
tasks.withType(GroovyCompile) {
    groovyClasspath += configurations.ivy
}&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;</description>
        </item><item>
            <title>Groovyスクリプト、grabおよびivyの設定</title>
            <link >https://cheroliv.com/blog/2019/0010_gradle_groovy_script_grab_ivy_configuration_post.html</link>
            <pubDate>Wed, 14 Aug 2019 00:00:00 +0000</pubDate>
            <guid isPermaLink="false">blog/2019/0010_gradle_groovy_script_grab_ivy_configuration_post.html</guid>
            <description>&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;チケットの件名はGradleビルドスクリプトの設定です。&amp;lt;br&amp;gt;
Groovyスクリプトを参照せずに使用できるようにしたい&amp;lt;br&amp;gt;
Gradleプロジェクトに私が添付したもの&amp;lt;br&amp;gt;
Gradleの外でこのGroovyスクリプトを実行できるようにしたい&amp;lt;br&amp;gt;
Ivy の外部依存関係取得のためのアノテーションがないまま&amp;lt;br&amp;gt;
性能またはコンパイルの問題を引き起こしに来ない&amp;lt;br&amp;gt;
Gradleビルドスクリプトの。&amp;lt;br&amp;gt;
構成を示すために、私は2つのスクリプトに依存しています：&amp;lt;br&amp;gt;
Gradle のビルドスクリプトと Groovy スクリプト。&amp;lt;br&amp;gt;
Groovy スクリプトは先頭の行 2 に含まれます、&amp;lt;br&amp;gt;
外部依存関係を取得するための指示&amp;lt;br&amp;gt;
Ivy依存マネージャーを使って。&amp;lt;br&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-Groovy hljs&amp;quot; data-lang=&amp;quot;Groovy&amp;quot;&amp;gt;#!/usr/bin/env groovy
@Grab(&amp;quot;commons-io:commons-io:2.6&amp;quot;)

import org.apache.commons.io.FileUtils

static String getSeparator() {
    System.getProperty(&amp;quot;file.separator&amp;quot;)
}

String from = &amp;quot;${System.getProperty(&amp;quot;user.home&amp;quot;)}${separator}.config${separator}transmission${separator}torrents&amp;quot;
String to = &amp;quot;${System.getProperty(&amp;quot;user.home&amp;quot;)}${separator}Documents${separator}torrents_completed&amp;quot;

File fromDlDir = new File(&amp;quot;${System.getProperty(&amp;quot;user.home&amp;quot;)}${separator}Téléchargements&amp;quot;)
File fromDir = new File(from)
File toDir = new File(to)

Collection&amp;amp;lt;File&amp;amp;gt; torrentFiles = FileUtils.listFiles(
        fromDir,
        [&amp;quot;torrent&amp;quot;] as String[],
        false)
torrentFiles.addAll(FileUtils.listFiles(
        fromDlDir,
        [&amp;quot;torrent&amp;quot;, &amp;quot;torrent.added&amp;quot;] as String[],
        false))


torrentFiles.empty ?: torrentFiles.each { it -&amp;amp;gt;
    FileUtils.copyFileToDirectory(it, toDir)
}
println torrentFiles.size()&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;build.gradleファイル、今、どのように調和させるかを見てみましょう。&amp;lt;br&amp;gt;
2つの依存関係管理ツール、ivyとGradle。 両者間の合意は行で行われます：&amp;lt;br&amp;gt;
26, 30, 37, 38 et 39&amp;lt;br&amp;gt;
それによって、私はGroovyスクリプトを手動で実行できます、&amp;lt;br&amp;gt;
そして Gradle のコンパイルは @Grab によって妨げられません。&amp;lt;br&amp;gt;
Groovyスクリプトの依存関係はGradleで提供する必要はありません。&amp;lt;br&amp;gt;
しかし、私は Gradle から Groovy スクリプトを実行できません。&amp;lt;br&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-Groovy hljs&amp;quot; data-lang=&amp;quot;Groovy&amp;quot;&amp;gt;plugins {
    id &amp;quot;java&amp;quot;
    id &amp;quot;groovy&amp;quot;
}

repositories {
    mavenCentral()
    jcenter()
}

sourceSets {
    main {
        java { srcDirs = [] }
        groovy { srcDirs =[&amp;quot;src/main/java&amp;quot;, &amp;quot;src/main/groovy&amp;quot;] }
        resources {
            srcDirs =[&amp;quot;src/main/resources&amp;quot;]
        }
    }
    test {
        java { srcDirs = [] }
        groovy { srcDirs =[&amp;quot;src/test/java&amp;quot;, &amp;quot;src/test/groovy&amp;quot;] }
    }
}

configurations {
    ivy
}

dependencies {
    ivy &amp;quot;org.apache.ivy:ivy:$ivy_version&amp;quot;
    implementation &amp;quot;org.codehaus.groovy:groovy-all:$groovy_version&amp;quot;
}



tasks.withType(GroovyCompile) {
    groovyClasspath += configurations.ivy
}&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;チケットの参照についてhttps://stackoverflow.com/a/18174033/837404[stackoverflow]&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;</description>
        </item><item>
            <title>Groovy: 少しの代数、最大公約数と最小公倍数</title>
            <link >https://cheroliv.com/blog/2019/0009_groovy_algebre_pgcd_ppmc_post.html</link>
            <pubDate>Tue, 13 Aug 2019 00:00:00 +0000</pubDate>
            <guid isPermaLink="false">blog/2019/0009_groovy_algebre_pgcd_ppmc_post.html</guid>
            <description>&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_ppmcは&amp;quot;&amp;gt;PPMCは&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;https://fr.wikipedia.org/wiki/Plus_petit_commun_multiple&amp;quot;&amp;gt;ウィキPPMCまたは最小公倍数&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;AlgebraUtils.groovy&amp;lt;br&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-groovy hljs&amp;quot; data-lang=&amp;quot;groovy&amp;quot;&amp;gt;package com.cheroliv.misc

import groovy.transform.CompileStatic

@CompileStatic
class AlgebraUtils {

    /**
     * Great common divisor
     * Plus grand commun diviseur(pgcd)
     * Great Common Divisor
     * @param a
     * @param b
     * @return
     */
    static Integer gcd(Integer a, Integer b) {
        !b ? a : gcd(b, a % b)
    }


    /**
     * Least common multiple
     * Plus petit commun multiplicateur(ppmc)
     * @param a
     * @param b
     * @return
     */
    static BigInteger lcm(Integer a, Integer b) {
        (a * b / gcd(a, b)) as BigInteger
    }

    static void main(String... args) {
        Integer a = 96
        Integer b = 28
        println &amp;quot;gcd($a, $b) = ${gcd(a, b)}&amp;quot;
        a = 790
        b = 990
        println &amp;quot;lcm($a, $b) = ${lcm(a, b)}&amp;quot;
    }
}&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;結果:&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;gcd(96, 28) = 4 最小公倍数(790, 990) = 78210&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;</description>
        </item><item>
            <title>Bash : find を使って拡張子でファイルを検索し、結果をファイルに出力する</title>
            <link >https://cheroliv.com/blog/2019/0008_bash_find_trouver_fichiers_par_extension_post.html</link>
            <pubDate>Mon, 12 Aug 2019 00:00:00 +0000</pubDate>
            <guid isPermaLink="false">blog/2019/0008_bash_find_trouver_fichiers_par_extension_post.html</guid>
            <description>&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;名前の条件でファイルを検索しています: .h または .cpp ファイルのリスト&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;$ find . -name &amp;#39;*.h&amp;#39; -o -name &amp;#39;*.cpp&amp;#39; + +&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;拡張子が .h と .cpp であるファイルのリスト&amp;lt;br&amp;gt;
結果は list_of_txt_files.list ファイルに保存されます。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;$ find . -name &amp;#39;*.h&amp;#39; -o -name &amp;#39;*.cpp&amp;#39; -print &amp;amp;gt; list_of_txt_files.list&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;拡張子が .chm のファイルのリストを探しています。&amp;lt;br&amp;gt;
そして私はこのリストを破壊する。&amp;lt;br&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;$ find . -name &amp;quot;*.chm&amp;quot; -type f -delete&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;</description>
        </item><item>
            <title>デジタルプロジェクトをウォーターフォール手法で管理する</title>
            <link >https://cheroliv.com/blog/2019/0015_projet_avec_methodologie_en_cascade_post.html</link>
            <pubDate>Thu, 1 Aug 2019 00:00:00 +0000</pubDate>
            <guid isPermaLink="false">blog/2019/0015_projet_avec_methodologie_en_cascade_post.html</guid>
            <description>&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_ニーズを分析し収集する&amp;quot;&amp;gt;ニーズを分析し、収集する&amp;lt;/h3&amp;gt;

&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_プロジェクト管理を定義する&amp;quot;&amp;gt;プロジェクト管理を定義する&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;imageblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;img src=&amp;quot;../../diagram/definir_projet.png&amp;quot; alt=&amp;quot;definir la gestion de projet&amp;quot;&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;imageblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;img src=&amp;quot;../../img/triangle_qcd.png&amp;quot; alt=&amp;quot;triangle_qcd&amp;quot;&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_プロジェクトを文脈化する&amp;quot;&amp;gt;プロジェクトを文脈化する&amp;lt;/h3&amp;gt;

&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_要件を分析し収集する&amp;quot;&amp;gt;要件を分析し、収集する&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;sect3&amp;quot;&amp;gt;
&amp;lt;h4 id=&amp;quot;_目標と成果物を明確にする&amp;quot;&amp;gt;目標と成果物を明確にする&amp;lt;/h4&amp;gt;

&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_読み取りグリッドを解読する&amp;quot;&amp;gt;読み取りグリッドを解読する&amp;lt;/h3&amp;gt;

&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect1&amp;quot;&amp;gt;
&amp;lt;h2 id=&amp;quot;_チームとともにプロジェクトのスコープを定めてください&amp;quot;&amp;gt;チームとともにプロジェクトのスコープを定めてください&amp;lt;/h2&amp;gt;
&amp;lt;div class=&amp;quot;sectionbody&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;imageblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;img src=&amp;quot;../../img/conductor.png&amp;quot; alt=&amp;quot;chef d&amp;amp;#8217;orchestre&amp;quot;&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_専門家に相談して解決策を見つける&amp;quot;&amp;gt;専門家に相談して解決策を見つける&amp;lt;/h3&amp;gt;

&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;sect2&amp;quot;&amp;gt;
&amp;lt;h3 id=&amp;quot;_プロジェクト管理の方法論を選択する&amp;quot;&amp;gt;プロジェクト管理の方法論を選択する&amp;lt;/h3&amp;gt;
&amp;lt;div class=&amp;quot;imageblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;img src=&amp;quot;../../img/cascading_planning.png&amp;quot; alt=&amp;quot;planning en cascade&amp;quot;&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;imageblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;img src=&amp;quot;../../img/Cycle_V_details.jpeg&amp;quot; alt=&amp;quot;cycle en V&amp;quot;&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;</description>
        </item><item>
            <title>PostgreSQLインスタンス内のデータベースを一覧表示する</title>
            <link >https://cheroliv.com/blog/2019/0014_list_all_databases_in_postgresql_post.html</link>
            <pubDate>Tue, 30 Jul 2019 00:00:00 +0000</pubDate>
            <guid isPermaLink="false">blog/2019/0014_list_all_databases_in_postgresql_post.html</guid>
            <description>&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;インストールしたくないhttps://www.pgadmin.org/[pgAdmin] ou &amp;lt;a href=&amp;quot;http://phppgadmin.sourceforge.net/&amp;quot;&amp;gt;phppgadmin&amp;lt;/a&amp;gt; ただし、すべてがコマンドラインに存在している。&amp;lt;br&amp;gt;
そのため、ターミナルを起動し、postgres ユーザーとして接続する必要があります。&amp;lt;br&amp;gt;
Postgresユーザーはデフォルトでpsqlアプリケーションを起動する権限を持つ唯一のユーザーです。 psqlはコマンドラインクライアントです。 (&amp;lt;a href=&amp;quot;https://fr.wikipedia.org/wiki/Interface_en_ligne_de_commande&amp;quot;&amp;gt;コマンドラインインターフェース&amp;lt;/a&amp;gt;) postgresql,&amp;lt;br&amp;gt;
ターミナルからコマンドラインでデータベースと通信できるようにするため&amp;lt;br&amp;gt;
接続するには、ターミナルを起動し、これを入力してください:&amp;lt;br&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;$ sudo -i -u postgres&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;PostgreSQLのコマンドプロンプトに直接接続し、ログインするには、次のように入力してください :&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;$ sudo -i -u postgres psql&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;PostgreSQLのインスタンスのデータベースを一覧表示するコマンドは次の通りです :&amp;lt;br&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-SQL hljs&amp;quot; data-lang=&amp;quot;SQL&amp;quot;&amp;gt;postgres=# \l&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;結果:&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;データベースの一覧 名前    | 所有者 | エンコーディング | ソート順 | 文字種 |    アクセス権&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;fiber     | tech         | UTF8     | fr_FR.UTF-8     | fr_FR.UTF-8  | =Tc/tech&amp;lt;br&amp;gt;
|              |          |                 |              | tech=CTc/tech fiberdev  | tech         | UTF8     | fr_FR.UTF-8     | fr_FR.UTF-8  | =Tc/tech&amp;lt;br&amp;gt;
|              |          |                 |              | tech=CTc/tech fiberweb  | tech         | UTF8     | fr_FR.UTF-8     | fr_FR.UTF-8  | =Tc/tech&amp;lt;br&amp;gt;
|              |          |                 |              | tech=CTc/tech postgres  | postgres     | UTF8     | fr_FR.UTF-8     | fr_FR.UTF-8  | template0 | postgres     | UTF8     | fr_FR.UTF-8     | fr_FR.UTF-8  | =c/postgres&amp;lt;br&amp;gt;
|              |          |                 |              | postgres=CTc/postgres template1 | postgres     | UTF8     | fr_FR.UTF-8     | fr_FR.UTF-8  | =c/postgres&amp;lt;br&amp;gt;
|              |          |                 |              | postgres=CTc/postgres (6行)&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;qを押して結果表示を終了する&amp;lt;br&amp;gt;
&amp;lt;br&amp;gt;
インスタンスのスキーマをリストするには postgresl.&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-sql hljs&amp;quot; data-lang=&amp;quot;sql&amp;quot;&amp;gt;postgres=# SELECT schema_name FROM information_schema.schemata;&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;結果&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;公共の インフォメーションスキーマ pg_catalog pg_toast_temp_1 pg_temp_1 pg_toast (6行)&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;ou&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-sql hljs&amp;quot; data-lang=&amp;quot;sql&amp;quot;&amp;gt;postgres=# SELECT nspname FROM pg_catalog.pg_namespace;&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;結果&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;pg_toast pg_temp_1 pg_toast_temp_1 pg_catalog information_schema 公開 (6 行)&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;</description>
        </item><item>
            <title>Groovy: ファイルを再帰的にリネームする</title>
            <link >https://cheroliv.com/blog/2019/0007_groovy_rename_recursively_files_post.html</link>
            <pubDate>Mon, 29 Jul 2019 00:00:00 +0000</pubDate>
            <guid isPermaLink="false">blog/2019/0007_groovy_rename_recursively_files_post.html</guid>
            <description>&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;私のテレビのビデオプレーヤーは、そのとおりに通す方法を持っている&amp;lt;br&amp;gt;
ファイルからファイルへ、連続して読み込む&amp;lt;br&amp;gt;
その再生モードは、1&amp;amp;#8230;&amp;amp;#8203;..mp4 から 10&amp;amp;#8230;&amp;amp;#8203;.mp4 へと移ります,&amp;lt;br&amp;gt;
そして、1&amp;amp;#8230;&amp;amp;#8203;mp4 から 2&amp;amp;#8230;&amp;amp;#8203;.mp4 までではない。&amp;lt;br&amp;gt;
問題は、ほぼ900のファイルとフォルダーがあることです。&amp;lt;br&amp;gt;
ビンゴはGroovyを使った操作の優れたユースケースです&amp;lt;br&amp;gt;
ファイル、リネーム、ファイル名内のパターン検索&amp;lt;br&amp;gt;
またはファイル。&amp;lt;br&amp;gt;
ここでの目的は、…で始まる名前を変更することです&amp;lt;br&amp;gt;
数字であり、かつその名前の2番目の文字&amp;lt;br&amp;gt;
数字ではありません。この名前に最初に0を追加します+&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;renameFilesToStartWithTwoDigit.groovy&amp;lt;br&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-groovy hljs&amp;quot; data-lang=&amp;quot;groovy&amp;quot;&amp;gt;#!/usr/bin/env groovy
/**
 * get a crossplateform separator
 * @return
 */
static String getSeparator() {
    System.getProperty(&amp;quot;file.separator&amp;quot;)
}
/**
 * rename file
 * @param file
 * @param newName
 * @return the renamed file
 */
static File rename(File file, String newName) {
    assert file.renameTo(file
            .parentFile.path +
            getSeparator() +
            newName)
    new File(file
            .parentFile.path +
            getSeparator() +
            newName)
}

String rootFolderPath = System.getProperty(&amp;quot;user.home&amp;quot;) +
        &amp;quot;/Bureau/ng-courses/Udemy - Angular 7 &amp;quot; +
        &amp;quot;(formerly Angular 2) - The Complete Guide&amp;quot;

File rootFolder = new File(rootFolderPath)
assert rootFolder.exists()
assert rootFolder.directory
assert rootFolder.canRead()

List&amp;amp;lt;File&amp;amp;gt; dirList = new ArrayList&amp;amp;lt;&amp;amp;gt;()

//Adding rootFolder in dirList
// just in case there is some files in it
dirList.add(rootFolder)

//looping to get list of directories
//recursively inside rootFolder
rootFolder.traverse { File file -&amp;amp;gt;
    !file.directory ?: dirList.add(file)
}

//looping through dirList
//to rename directories filling criterias
for (int i = dirList.size() - 1; i &amp;amp;gt;= 0; i--) {
    Character[] chars = dirList.get(i).name.chars
    !(chars[0].digit &amp;amp;amp;&amp;amp;amp; !chars[1].digit) ?:
            dirList.set(i, rename(dirList.get(i),
                    &amp;quot;0${dirList.get(i).name}&amp;quot;))
    if (dirList.get(i).directory) {
        //looping through directory
        //to rename file filling criterias
        dirList.get(i).listFiles().each { File f -&amp;amp;gt;
            Character[] cs = f.name.chars
            !(cs[0].digit &amp;amp;amp;&amp;amp;amp; !cs[1].digit) ?:
                    rename(f, &amp;quot;0${f.name}&amp;quot;)
        }
    }
}&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;</description>
        </item><item>
            <title>Groovy: 条件によるファイル検索、選択のコピー</title>
            <link >https://cheroliv.com/blog/2019/0006_groovy_find_files_copy_to_post.html</link>
            <pubDate>Fri, 19 Jul 2019 00:00:00 +0000</pubDate>
            <guid isPermaLink="false">blog/2019/0006_groovy_find_files_copy_to_post.html</guid>
            <description>&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;このスクリプトの目的はファイルを検索することです,&amp;lt;br&amp;gt;
親ディレクトリから; 選択を取得&amp;lt;br&amp;gt;
リストの中。最後にこのファイルリストをコピーする&amp;lt;br&amp;gt;
destination ディレクトリにおいて、これを Groovy で行います。&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;findCopyTo.groovy&amp;lt;br&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-groovy hljs&amp;quot; data-lang=&amp;quot;groovy&amp;quot;&amp;gt;#!/usr/bin/env groovy
@Grab(&amp;quot;commons-io:commons-io:2.6&amp;quot;)

import groovy.io.FileType
import org.apache.commons.io.FileUtils

/**
 * un separateur OS independant
 * @return
 */
static String getSep() {
    System.getProperty(&amp;quot;file.separator&amp;quot;)
}
/**
 * la liste des fichiers dont le titre contient un item
 * de la liste des motifs
 *
 * @param path
 * @param motifs
 * @return la liste des chemins complet de fichiers
 */
static List&amp;amp;lt;String&amp;amp;gt; findFilesContainingMotifs(
        String path,
        List&amp;amp;lt;String&amp;amp;gt; motifs) {
    List&amp;amp;lt;String&amp;amp;gt; filePathResultList = new ArrayList&amp;amp;lt;&amp;amp;gt;()
    new File(path)
            .eachFileRecurse(FileType.FILES) {
                if (it.name.toLowerCase().contains(&amp;#39;cucumber&amp;#39;)) {
                    filePathResultList.add it.path
                }
            }
    filePathResultList
}

/**
 * copy vers la liste des fichiers
 * @param files
 * @param to
 */
static void copyFilesTo(List&amp;amp;lt;String&amp;amp;gt; files, String to) {
    File toDirDest = new File(to)
    files.each { String filepath -&amp;amp;gt;
        File file = new File(filepath)
        //si le dernier caractere de to n&amp;#39;est pas un separateur
        // alors ajoute le a la chaine
        (to.substring(to.length() - 1) == sep) ?: to.concat(sep)
        if (to + file.name != filepath) {
            FileUtils.copyFileToDirectory(file, toDirDest)
            file.delete()
        }
    }
}
/**
 * la list des arguments
 */
String userName = System.getProperty(&amp;quot;user.name&amp;quot;)
List&amp;amp;lt;String&amp;amp;gt; motifs = [&amp;#39;cucumber&amp;#39;]
String path = &amp;quot;/media/$userName/320/Books/&amp;quot;
String to = &amp;quot;/media/$userName/320/Books/bdd/&amp;quot;
/**
 * lappel aux methodes
 */
copyFilesTo(findFilesContainingMotifs(path, motifs), to)

//affiche moi les fichiers déplacés
findFilesContainingMotifs(path, motifs).each {
    println it
}&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;</description>
        </item><item>
            <title>Groovy: ファイルの操作, 検索と削除</title>
            <link >https://cheroliv.com/blog/2019/0005_groovy_manipulation_files_post.html</link>
            <pubDate>Thu, 18 Jul 2019 00:00:00 +0000</pubDate>
            <guid isPermaLink="false">blog/2019/0005_groovy_manipulation_files_post.html</guid>
            <description>&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;ここでは、ビルドプロジェクトにおけるプロパティのロードについて説明します。https://docs.gradle.org/current/userguide/userguide.html[gradle]&amp;lt;br&amp;gt;
それがコードで利用できないままです。&amp;lt;br&amp;gt;
プロパティは ~/.gradle/gradle.properties ディレクトリの gradle.properties ファイルに設定されます。&amp;lt;br&amp;gt;
~ は、ユーザーセッションのルートを表すシンボリック変数 HOME_PATH のショートカットです: そのhttps://fr.wikipedia.org/wiki/R%C3%A9pertoire_personnel[ホームディレクトリ].&amp;lt;br&amp;gt;
同様にビルドプロジェクトの中でhttps://maven.apache.org/guides/index.html[maven]、と `~/.m2/settings.xml このスクリプトの目的は、指定されたパターンに一致するファイルを削除することです。&amp;lt;br&amp;gt;
変数 strCriteria に。 そのために私はそれを使うhttps://fr.wikipedia.org/wiki/Fermeture_(informatique)[クロージャ]: each, findAll,  collect&amp;lt;br&amp;gt;
さらに、基準文字列を分割する StringTokenizer クラス&amp;lt;br&amp;gt;
それを取得して文字列のリストを得るために もし私が掃除するフォルダのファイルのうちの1つが、その名前に1つのパターンを含んでいる場合&amp;lt;br&amp;gt;
そうすると、結果のリストに追加されることで破壊の対象となる候補となる。&amp;lt;br&amp;gt;
最後に一行の小さな例としてhttps://en.wikipedia.org/wiki/Elvis_operator[エルビス演算子]&amp;lt;br&amp;gt;
filemanip.groovy&amp;lt;br&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-groovy hljs&amp;quot; data-lang=&amp;quot;groovy&amp;quot;&amp;gt;#!/usr/bin/env groovy
//Mes criteres de selection des fichiers à detruire
String strCriteria = &amp;quot;Dummies Dummie ajax Objective-C Windows blackberry &amp;quot; +
        &amp;quot;wordpress joomla ios c# f# rails ruby flex asp flash Dreamweaver adobe &amp;quot; +
        &amp;quot;CoffeeScript c++ .chm .epub .rar .zip .tar drupal drupals .net php javascript &amp;quot; +
        &amp;quot;.js iphone ipad js _js facebook gwt vaadin linq python py zope window &amp;quot; +
        &amp;quot;3D scala gaming active_directory tomcat jboss glassfish microsoft 2d &amp;quot; +
        &amp;quot;lego blogger blog cocoa dojo dom dotnetnuke eclipse .gz unity sharepoint &amp;quot; +
        &amp;quot;.tgz iwork filemaker .doc .txt&amp;quot;


//repertoire personnel
String userDir = System.getProperty(&amp;quot;user.home&amp;quot;)
//un separateur de chemin crossplatform
String sep = System.getProperty(&amp;quot;file.separator&amp;quot;)
//la variable symbolique
String sym_books_vrac_path = &amp;quot;books_vrac_path&amp;quot;

//le chemin de mon fichier gradle.properties hors projet
String propertiesFilePath = userDir
        .concat(&amp;quot;${sep}.gradle${sep}gradle.properties&amp;quot;)


File propertiesFile = new File(propertiesFilePath)


//je m&amp;#39;aassure que le fichier existe et que ce n&amp;#39;est pas un dossier
assert propertiesFile.exists() &amp;amp;amp;&amp;amp;amp; !propertiesFile.directory

Properties gradleProperties = new Properties()

//on boucle avec un inpustream sur le fichier
//gradle.properties pour peupler ma variable gradleProperties
propertiesFile.withInputStream { InputStream it -&amp;amp;gt;
    gradleProperties.load(it)
}

//le chemin du dossier books_vrac est la valeur de notre clé books_vrac_path
String pathVracDir = gradleProperties.get(sym_books_vrac_path)

//j&amp;#39;ai récuperé tous ces livres en tapant cette commande dans le terminal
//wget -m -np -c -R &amp;quot;index.html*&amp;quot; &amp;quot;http://the-eye.eu/public/Books/IT%20Various/&amp;quot;

//on ouvre le dossier dont le chemin est dans la variable pathVracDir
// on s&amp;#39;assure qu&amp;#39;il existe et que c&amp;#39;est un dossier
File vracDir = new File(pathVracDir)
assert vracDir.exists() &amp;amp;amp;&amp;amp;amp; vracDir.directory


//separer les élèments de ma liste de critère
StringTokenizer tokenizer = new StringTokenizer(strCriteria)

//la liste de critere
List&amp;amp;lt;String&amp;amp;gt; criteriaList = new ArrayList&amp;amp;lt;&amp;amp;gt;()

//j&amp;#39;itère sur les tokens et je construit ma liste de token,
// mot clef critère de recherche
tokenizer.each { String it -&amp;amp;gt;
    criteriaList.add(it.toLowerCase())
}

//je collect tous les noms de fichier dans le dossier
List&amp;amp;lt;String&amp;amp;gt; fileNameList = vracDir
        .listFiles()
        .collect { File it -&amp;amp;gt;
            it.directory ?: it.name
        }

// je collect les noms de fichier qui contiendraient un des criteres
List&amp;amp;lt;String&amp;amp;gt; resultList = fileNameList.findAll { String name -&amp;amp;gt;
    criteriaList.findAll { String crit -&amp;amp;gt;
        name.toLowerCase().contains(crit)
    }
}

// je parcours ma liste de résultat pour les effacer
resultList.each { String fileName -&amp;amp;gt;
    assert new File(vracDir.path + sep + fileName).delete()
}

println fileNameList.size()
println resultList.size()
resultList.empty ?: println(vracDir.path + sep + resultList.first())&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;</description>
        </item><item>
            <title>Groovy: String内の文字シーケンスを置換し、ファイルから Properties をロードする</title>
            <link >https://cheroliv.com/blog/2019/0004_groovy_replace_string_load_properties_post.html</link>
            <pubDate>Wed, 17 Jul 2019 00:00:00 +0000</pubDate>
            <guid isPermaLink="false">blog/2019/0004_groovy_replace_string_load_properties_post.html</guid>
            <description>&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;これはGroovyで動作するコードの一部です,&amp;lt;br&amp;gt;
String内の文字シーケンスのすべての出現を変更を目的とするために&amp;lt;br&amp;gt;
そして、.properties ファイルを properties オブジェクトに読み込む。&amp;lt;br&amp;gt;
文字列内でコマンドを実行する。&amp;lt;br&amp;gt;
replaceTextinFile.groovy&amp;lt;br&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-groovy hljs&amp;quot; data-lang=&amp;quot;groovy&amp;quot;&amp;gt;#!/usr/bin/env groovy
println System.getProperty(&amp;quot;user.home&amp;quot;)

static String getSeparator_() {
    System.getProperty(&amp;quot;file.separator&amp;quot;)
}

String separator = separator_

String path = System.getProperty(&amp;quot;user.home&amp;quot;)
        .concat(&amp;quot;${separator}.gradle&amp;quot; +
                separator +
                &amp;quot;gradle.properties&amp;quot;)

File propertiesFile = new File(path)

assert propertiesFile.exists() &amp;amp;amp;&amp;amp;amp; !propertiesFile.directory

Properties gradleProperties = new Properties()

propertiesFile.withInputStream { InputStream it -&amp;amp;gt;
    gradleProperties.load(it)
}

String user_name = gradleProperties.getProperty(&amp;quot;user_name&amp;quot;)

String text
String resultText
text = new File(&amp;quot;${System.getProperty(&amp;quot;user.home&amp;quot;)}&amp;quot; +
        separator +
        &amp;quot;src&amp;quot; +
        separator +
        &amp;quot;cheroliv.github.io&amp;quot; +
        separator +
        &amp;quot;src&amp;quot; +
        separator +
        &amp;quot;main&amp;quot; +
        separator +
        &amp;quot;resources&amp;quot; +
        separator +
        &amp;quot;eco_space.txt&amp;quot;).text

String to = separator +
        &amp;quot;media&amp;quot; +
        separator +
        &amp;quot;${user_name}&amp;quot; +
        separator +
        &amp;quot;320&amp;quot; +
        separator +
        &amp;quot;videoCours&amp;quot; +
        separator
String from = &amp;quot;${System.getProperty(&amp;quot;user.home&amp;quot;)}&amp;quot; +
        separator +
        &amp;quot;p2p&amp;quot; +
        separator

resultText = text.replace(to, from)

println resultText

//execute command line in a string
println &amp;quot;rsync -avr ${resultText} ${to}&amp;quot;.execute().text&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;</description>
        </item><item>
            <title>Groovy: ASCII文字</title>
            <link >https://cheroliv.com/blog/2019/0003_groovy_char_ascci_post.html</link>
            <pubDate>Wed, 10 Jul 2019 00:00:00 +0000</pubDate>
            <guid isPermaLink="false">blog/2019/0003_groovy_char_ascci_post.html</guid>
            <description>&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;以下は Groovy で動作するコードの一部で、テキスト ファイルを生成します。&amp;lt;br&amp;gt;
ASCII表の最初の256個の読み取り可能な文字&amp;lt;br&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-groovy hljs&amp;quot; data-lang=&amp;quot;groovy&amp;quot;&amp;gt;#!/usr/bin/env groovy
import java.nio.charset.StandardCharsets

List&amp;amp;lt;Character&amp;amp;gt; chars = new ArrayList&amp;amp;lt;&amp;amp;gt;()
int j = 0
Character jumpLine = &amp;#39;\n&amp;#39;

256.times { Integer idx -&amp;amp;gt;
    if (Character.isAlphabetic(idx) || Character.isDigit(idx)) {
        if (j % 10 == 0 &amp;amp;amp;&amp;amp;amp; j != 0) {
            chars.add(jumpLine)
            chars.add(idx as char)
        } else chars.add(idx as char)
        j++
    }
}

String seperator = System.getProperty(&amp;quot;file.separator&amp;quot;)

String path = &amp;quot;${System.getProperty(&amp;quot;user.home&amp;quot;)}${seperator}ascii.txt&amp;quot;
File speCharFile = new File(path)

if (speCharFile.exists() &amp;amp;amp;&amp;amp;amp; !speCharFile.directory) {
    speCharFile.text = &amp;quot;&amp;quot;
} else {
    speCharFile.createNewFile()
}

String text = new String()

chars.each { Character it -&amp;amp;gt;
    text = it == jumpLine ? &amp;quot;$text$it&amp;quot; : &amp;quot;$text $it &amp;quot;
}

speCharFile.setText(text, StandardCharsets.UTF_8.toString())&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;私はファイルを &amp;lt;code&amp;gt;spe_char.groovy&amp;lt;/code&amp;gt; と名付けました,&amp;lt;br&amp;gt;
ファイルがあるフォルダーから&amp;lt;br&amp;gt;
ターミナルを開いてコピー＆ペーストしてスクリプトを実行する＋&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;listingblock&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;content&amp;quot;&amp;gt;
&amp;lt;pre class=&amp;quot;highlightjs highlight&amp;quot;&amp;gt;&amp;lt;code class=&amp;quot;language-bash hljs&amp;quot; data-lang=&amp;quot;bash&amp;quot;&amp;gt;$ groovy spe_char.groovy&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;結果:&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;paragraph&amp;quot;&amp;gt;
&amp;lt;p&amp;gt;0  1  2  3  4  5  6  7  8  9 A  B  C  D  E  F  G  H  I  J K  L  M  N  O  P  Q  R  S  T U  V  W  X  Y  Z  a  b  c  d e  f  g  h  i  j  k  l  m  n o  p  q  r  s  t  u  v  w  x y  z  ª  µ  º  À  Á  Â  Ã  Ä Å  Æ  Ç  È  É  Ê  Ë  Ì  Í  Î Ï  Ð  Ñ  Ò  Ó  Ô  Õ  Ö  Ø  Ù Ú  Û  Ü  Ý  Þ  ß  à  á  â  ã ä  å  æ  ç  è  é  ê  ë  ì  í î  ï  ð  ñ  ò  ó  ô  õ  ö  ø ù  ú  û  ü  ý  þ  ÿ&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;</description>
        </item>

    </channel>
</rss>
