後悔しないための技術選定とアーキテクチャ設計

〜不確実性を乗りこなすための原則〜

株式会社レクター 代表取締役 広木大地

自己紹介

広木 大地

株式会社レクター代表取締役

1983年生まれ。筑波大学大学院を卒業後、2008年に新卒第1期として株式会社ミクシィに入社 アーキテクトとして、技術戦略から組織構築などに携わる 同社メディア開発部長、開発部部長、サービス本部長執行役員を務めた後、2015年退社 現在は、株式会社レクターを創業し、技術と経営をつなぐ技術組織のアドバイザリーとして、多数の会社の経営支援を行っている。 一般社団法人日本CTO協会理事、朝日新聞社社外CTO。
w:%

目次

1
アーキテクチャという概念の理解
2
アーキテクチャの持つ権力の発生源
3
ソフトウェアコントローラビリティと技術的負債
4
目的と手段の階層構造
5
ソフトウェアコントローラビリティの不等式
アーキテクチャという概念の理解

「アーキテクチャ」とは何だろうか。

この根本理解が技術選定を考える上で重要なポイントになる。

アーキテクチャという概念の理解

「アーキテクチャ」に対する一般的なイメージ

  • インフラ設計図のような青写真──機能やデータがどこに配置され、どう結び付くかを俯瞰で示す全体像。

  • システムの骨格とルール──技術スタックやモジュール分割、データフローなど「こう作るべき」を規定する枠組み。

  • 将来への建築基準──性能・安全性・保守性を支え、変更や拡張の自由度を左右する長期的な基盤。

アーキテクチャという概念の理解

「アーキテクチャ」の本質的な意味

建築から哲学、テクノロジーまで幅広い分野で使われ、人間の行動様式や社会関係を規定する重要な要素となっている。

建築物が人の動きを決めるように、社会制度やテクノロジーのアーキテクチャも私たちの行動や権力関係に影響を与えている。

アーキテクチャという概念の理解

ローレンス・レッシグのアーキテクチャ

  • アーキテクチャは、人々の行動を規制する4つの力(法、社会規範、市場、アーキテクチャ)の1つとして定義される

  • 「ある選択肢を選びやすく/選びにくくする」 という性質を環境に与えることで、人々の行動を自発的に促す仕組み

  • デジタル空間では、ソフトウェアやハードウェアの技術的構造(コード)が人間の行動を制御する力として機能する

アーキテクチャという概念の理解

敵対的"アーキテクチャ"と呼ばれるベンチ

  • 鉄パイプ付きベンチ → 長時間滞在を抑制

アーキテクチャという概念の理解

日常のアーキテクチャの例

  • 鉄パイプ付きベンチ

    • → 長時間滞在を抑制
  • ソフトウェアでも同様に行動を誘導する構造がある

    • 3 重認証で誤操作防止 vs. UX 低下
    • レコメンドエンジンはある商品を買い安く
  • 構造が振る舞いを規定する と体感できる

アーキテクチャという概念の理解

アーキテクチャとは、

ある選択肢を選びにくくし、

ある選択肢を選びやすくさせる権力構造

アーキテクチャという概念の理解

アーキテクチャの本質

  • 目に見えない “力” を発生させる環境設定

    • ある選択肢を選びにくくし、
    • ある選択肢を選びやすくさせる構造
  • 社会にもベンチにも Web サービスにも存在

    • たとえば、かつての Webフレームワークは、「Webサービス」に特化。
      APIだけを作ろうとすると過不足が出やすい。
  • この構造の力を利用して、
    メリットが得られるようにする活動がアーキテクティング

アーキテクチャの持つ権力の発生源

この力は何によって発生しているのか。

アーキテクチャの持つ権力の発生源

権力・依存・交換可能性の関係としてとらえる

  • 選択肢を持つ側が権力を持ち、持たない側を依存と呼ぶ。
  • 別の選択肢を「選べる側」と別の選択肢を「選べない側」
  • 交換可能性が権力(目に見えない力)の源泉

アーキテクチャの持つ権力の発生源

交換可能性が生み出す権力構造を具体例で理解する

モテる人と恋愛の関係性
モテる人✕恋愛
配送業界の交渉力
配送業界の値上げ交渉力↗
エンジニア市場
エンジニア市場

どれも「交換可能性」がパワーバランス(権力構造)を決定

アーキテクチャの持つ権力の発生源

ソフトウェアで考える交換可能性

  • 交換可能性が低い
    • 「依存している側」が理不尽を引き受けること=技術的負債
  • 交換可能性が高い
    • 別の選択を持ち、変化に適応できるメリット=アーキテクチャ
アーキテクチャの持つ権力の発生源

技術的負債とアーキテクチャの定義

アーキテクチャの持つ権力の発生源

アーキテクチャにおいて交換可能性が重要

交換可能性を高める試み

インタフェース抽象化
実装を交換できる
マイクロサービス
サービス毎交換できる
コンテナ/IaC
インスタンスやベンダーを交換できる

交換可能性を補助線にすると、

良いアーキテクチャとそうでないアーキテクチャが見えてくる。

アーキテクチャの持つ権力の発生源

権力・依存・交換可能性

選択肢を持つ側が強者となり、選択肢を持たない側は従属する関係性が生まれる。この依存関係が理不尽さや技術的負債を生み出す原因となる。

そのため、交換可能性の設計は本質的に権力の再配分を意味するのです。

ソフトウェアコントローラビリティと技術的負債

技術的負債問題の再定義

  • 古いシステム=技術的負債ではない。

    • 組織が必要な速度で交換(変更)できる能力を失うことが課題
    • 変化が必要なければ、技術的負債問題 も存在しない。
  • 技術的意思決定の副作用(時間とともに実装とドメイン/ビジネス知識の差分が生じた状態)は常に発生しうる。

  • 問題は、間違った意思決定を修正できないこと

    • 再設計には、これまでの累積工数を短い工期で再構築する組織能力が必要
    • 技術選定の「ツケ」を払うのは本人だけとは限らない。
ソフトウェアコントローラビリティと技術的負債

ソフトウェアコントローラビリティの喪失が課題

ソフトウェアコントローラビリティと技術的負債

技術選定を考える上でのポイント

  • 起こりうる変化=不確実性に対して、組織がソフトウェアを「交換」できることが大事

  • 不確実性を先読みすることは難しい。

    • だったら、最大限疎結合で柔軟な設計をする必要がある?
    • 全てにおいて柔軟なコードは、「eval」つまり何も書かないこと
  • 何かをアーキテクティングするのであれば、同時に何をしないのかを決める必要がある。

    • 不確実性の発生源を捉える必要がある。
    • 変わりうるもの/変わり得ないものは何か。
ソフトウェアコントローラビリティと技術的負債

依存が避けられないのなら、何に依存すべきか。

  • 抽象依存原則 (Dependency Inversion Principle)
    • より抽象的なものに依存すべきである。
  • 安定依存原則 (Stable Dependencies Principle)
    • より安定的なものに依存すべきである。
  • 安定抽象等価原則 (Stable Abstractions Principle)
    • 安定性と抽象性は等価であるべきである。
  • 非循環参照原則 (Acyclic Dependencies Principle)
    • 依存関係は非循環であるべきである。
  • 開放閉鎖原則 (Open-Closed Principle)
    • あるひとつの理由で変わるものは、ひとつの領域に閉じているべきである。
ソフトウェアコントローラビリティと技術的負債

アーキテクチャ設計プロセスと進化

技術的意思決定の副作用(時間とともに実装とドメイン/ビジネス知識の差分が生じた状態)が避けられないのなら、抽象構造を先に発見するか、後から発見するか。

  • ドメインモデルとは、「問題解決の抽象構造」
  • ドメインモデルの蒸留とは、「本質的なドメインモデルの構造が見つかること」
  • 長期間にわたってプロダクトを改良するには、「継続的蒸留」が必要
ソフトウェアコントローラビリティと技術的負債

進化的アーキテクチャ

  • 進化的アーキテクチャ:継続的なリファクタリングとリリースを前提に、要求への適応度が高い方に漸進的に変化
  • 技術的負債を「適応度の低いアーキテクチャ」と捉え直す。
  • 適応度関数を定義し、継続的に測定する。
  • 進化させるための組織文化を重要視し、組織とアーキテクチャの連動を前提。
目的と手段の階層構造

変化が起きたときにすばやく適応できる必要がある。

しかし、組織能力には限界がある。

どのように良い設計を評価したらよいか。

目的と手段の階層構造

ソフトウェアの目的論的な抽象構造

静的に定まった抽象ではなく、動的に目的に沿って再発見される抽象構造

目的と手段の階層構造

目的と手段の階層

  • 一般的に目的は変化しにくい。
  • 目的に対して手段は変化しやすい。
  • 例えば、幸せになりたい
    • そのためにお金持ちになりたい = この手段は別でも良い。
    • そのためにモテたい = べつにモテなくても良い。
    • モテるために痩せたい。
      • 痩せてもモテるとは限らない。
  • 目的と手段は階層構造になっている。
目的と手段の階層構造

ペースレイヤリング

ペースレイヤリング(Pace Layering)とは、思想家であり作家のスチュワート・ブランド(Stewart Brand)が提唱した概念。

  • 変化のペースが異なる階層が、緩やかな土台が速い層を支える構造。
  • 建築におけるペースレイヤリング(用地、構造、外装、設備、間取り、什器)。
  • 変わりにくいものがレジリエンスを、変わりやすいものが適応力をもたらす。
ペースレイヤリング
目的と手段の階層構造

ソフトウェアにおけるペースレイヤリング

  • システムを変化速度に応じて、
    遅い「SoR (System of Record:記録のシステム)」と
    速い「SoE (System of Engagement:エンゲージメントのシステム)」
    の2層に分けて捉える

    • SoRはデータの正確性/安定性を重視する基幹システムであり、変更は慎重。
    • SoEはUXと俊敏性を重視し、市場変化に素早く対応するユーザー接点。
  • この変化速度の異なる2層を分離して設計・開発することで、基盤(SoR)の安定性を損なうことなく、顧客接点(SoE)での迅速な改善やイノベーションを可能にし、安定性と俊敏性の両立。

目的と手段の階層構造

要求のオニオンモデル

ソフトウェア要求が多層的な外部制約の中で定義される考え方。

中心に至るまで ソフトウェア社会・環境顧客企業業務・ユーザITシステム の層がある。

各層からの制約(法律、顧客要望、企業戦略、業務プロセス、IT基盤など)が段階的に具体化され、要求を形作る。

目的と手段の階層構造

ビジネスの階層構造

目的と手段の階層構造がある。目的のために手段は常に変化しうる。

  • ミッション:会社が存在する限り変わらない根本的な存在意義
  • ビジョン:数年後に実現したい具体的な未来像
  • 戦略:1年〜3ヶ月の期間でビジョン達成のための方向性
  • 戦術:半年〜1年の期間で戦略を実行するための具体的手段
  • 施策:戦術をさらに細分化した短期的な実行計画

=> 目的と手段が階層構造がビジネスアーキテクチャ

目的と手段の階層構造

不確実性の発生源とその構造

  • ビジネスには目的と手段をベースとした階層構造(アーキテクチャ)がある。
  • ソフトウェア要求は、社会、法律、ビジネス、業務の要に多層的に影響を与える構造にある。
  • 社会や法律、業務、顧客にはことなる変化のペースがあり、構造物はそれに対応した堅牢性と適応性が求められる。
  • ソフトウェアは目的論的な抽象構造でより安定した抽象に依存し、より上位の目的に対して手段を交換できる必要がある。
目的と手段の階層構造

社会構造とビジネスが不確実性の波を引き起こす。

アーキテクチャはプリズムのように周波数成分に分解した構造

変化に相当する部分を交換ができる必要がある。

目的と手段の階層構造

アーキテクチャと不確実性のプリズム

目的と手段の階層構造

これらの原理を踏まえて、アーキテクチャ設計や技術選定で何を考えるか。

ソフトウェアコントローラビリティの不等式

ソフトウェアコントローラビリティの不等式

ライフサイクル x 依存性 x 交換リスク < 組織ケイパビリティ

ソフトウェアコントローラビリティの不等式

ライフサイクル

  • ソフトウェアサイズはどのぐらいか、どのぐらいの成長するか
    • 1万行以下なのか、100万行をこえるのか。
  • どのぐらいの期間利用するものなのか
    • 1回〜数回なのか、それとも数年、数十年つかうのか。
  • どういうときに必要なくなるものなのか
    • スポットのサービス終了、事業終了、法改正など
  • 概念検証なのか/実サービスなのか

サイズが大きく寿命が長いものほど、重要な意思決定になる。

ソフトウェアコントローラビリティの不等式

ライフサイクル

技術選定/アーキテクチャ設計に時間をかけるべきか

ソフトウェアコントローラビリティの不等式

ライフサイクルは読めるのか

  • PMFするまでは試行錯誤をしないといけない。
  • PMFしたらプロトタイプを捨てるつもりが、できない。
  • PMF後のリアーキテクチャはセカンドシステム症候群に陥る。
ソフトウェアコントローラビリティの不等式

マイクロサービス化のスイートスポット

ソフトウェアコントローラビリティの不等式

モジュールの依存性

依存性の高いものほど、高い組織ケイパビリティ

  • どこに責任分解点があるか
    • APIやワークフローの中のプロトコルで区切られているか
  • 多くのものから依存されるパーツか、そうじゃないか
    • ライブラリかフレームワークか
  • 依存性は分解できるか
ソフトウェアコントローラビリティの不等式

依存性の分析:フレームワークとライブラリの違い

ソフトウェアコントローラビリティの不等式

依存性の分析

  • バッテリー同梱か
    • フルスタックフレームワークのようにすぐに使えるが、依存性が高いものか
  • UNIX哲学か
    • 一つのことをうまくやり依存性が低いが、常にオーケストレーションが必要なものか

コミュニティサイズを前者の方が造りやすいが、後者の方が交換可能性が高い。

ソフトウェアコントローラビリティの不等式

クラウドサービスの依存性

  • 標準化されコモディティになっている
    • IaaS、コンテナ仮想化、k8sなど
  • 独自のインタフェースにアプリケーションが依存している
    • PaaSやIDaaSなど
  • クラウドマイグレーション/ リパトリエーションの可能性は0ではない。
    • 強烈な通貨安 / 関税 / アマゾンライバル企業からの買収 / 経済安保
ソフトウェアコントローラビリティの不等式

交換リスクの分析

  • 交換/修正の頻度はどのぐらいか。
  • ビジネスアーキテクチャのどこに位置しているか
    • レコメンドエンジンはより良い精度のエンジンがあれば交換される
    • OSSのインタフェースは露出するべきか、隠蔽すべきか。
  • 要求のオニオンモデルのどこから変更を要請されるか
    • 税額計算モジュールは、法改正によって変更を要請される
    • カスタマーサポート向けUIは、業務改善などによって変更を要請される
  • 技術のマクロトレンドのどこから変更を要請されるか
  • エンドオブライフのタイミングはいつくるのか、どこまでサポートされるのか。
ソフトウェアコントローラビリティの不等式

ステークホルダーインタビュー

ビジネスアーキテクチャを理解する

  • Why→When→How で目的階層を掘る
  • POV テンプレで観点を文章化
  • 組織ごとに "言語化コスト" が違う

先々のことを言語化するのは、苦手なことが多い。うまくヒアリングしたり、自らも理解していく必要がある。

ソフトウェアコントローラビリティの不等式

不確実性ストーミング

  • 不確実性を質より量でブレスト
  • 発生確率×影響度マッピング
  • 心理的安全性のある環境が大事
  • 規制/人事/税制 もリスクソース
ソフトウェアコントローラビリティの不等式

交換リスクの分析と依存性

  • 交換リスク(交換する理由)と依存性は、一致しているか。
ソフトウェアコントローラビリティの不等式

ソフトウェアコントローラビリティの不等式

ライフサイクル x 依存性 x 交換リスク < 組織ケイパビリティ

ソフトウェアコントローラビリティの不等式

組織ケイパビリティ

組織ケイパビリティは、自社とコミュニティ分かれる

  • 自社ケイパビリティ
    • 自分たちでソフトウェアを交換することができるか。
  • コミュニティケイパビリティ(OSSや外部サービス等)
    • コミュニティはライブラリやサービスを維持・発展できるか。
ソフトウェアコントローラビリティの不等式

自社ケイパビリティ

  • 技術スタックに対する社内の知識・経験レベル
    • 既存システムの理解度や新技術への適応能力を含む
  • チームの規模と専門性の分布
    • 特定技術に依存する場合、属人化リスクが高まる
  • 開発・運用プロセスの成熟度
    • CI/CD、テスト自動化、モニタリングなどの整備状況
  • 技術的負債への対応と組織文化
    • リファクタリングの優先度付けやADRなどの知識共有の仕組み
ソフトウェアコントローラビリティの不等式

自社ケイパビリティ:

アーキテクチャ・ディシジョン・レコード (ADR)

  • 目的: アーキテクチャの意思決定を「何を」と「なぜ」から記録する軽量文書。

  • 価値: 知識の属人化防止、意思決定の透明性確保、組織の記憶として機能。

  • 負債管理: 過去の決定理由を参照可能にし、将来の変更判断と技術的負債管理を支援。

  • 実践: リポジトリ内でマークダウン形式の簡潔な文書として管理し、日付・番号で整理。

ソフトウェアコントローラビリティの不等式

コミュニティケイパビリティ

  • 数名のコミュニティが提供している?
  • 数百人規模のコミュニティが提供している?
  • 小中規模の1社が提供している?
  • 大規模の1社が主に提供している?
  • 大規模の複数社がファウンデーションをもって提供している?
  • 実際に何名がどの頻度でコントリビュートしている?
  • 開発ロードマップが発表されてる?
  • その技術に関する求人票は多い?
ソフトウェアコントローラビリティの不等式

コミュニティケイパビリティのガバナンス要素

  • 重力圏"を持つエコシステムが勝つ

    • 周辺ツールセットの充実や導入コストの低さ、エコシステムがもっとも大きいものに重力が生まれる。
  • ロードマップなきリリースは、渡し船なき川渡り

    • 定期リリースと公開ロードマップがないプロジェクトは、渡し船を待つ群衆のように開発者を足止めする。
  • 資金は炎、コミュニティは酸素

    • 企業の後ろ盾は火を灯すが、酸素—多様なコントリビュータ—がなければ炎は長く持たない。
  • 求人票が消えた技術は、緩慢な EOL 宣言に等しい

    • 人材市場の温度は最速の健康指標。求人と学習イベントが減った瞬間、衰退曲線は滑り出す。
ソフトウェアコントローラビリティの不等式

気に入ったサービス/ソフトウェアなら、

コミュニティに積極参加していくことで、

みずから盛り上げていくのも大事

ソフトウェアコントローラビリティの不等式

技術選定/アーキテクチャ設計は難しいが、「失敗」をリカバリーできる体制やチーム、組織、コミュニティを作り上げることが最も重要

生成AIでなにがかわるか。

生成AIエージェントでこれらはどう変わる?

  • 変更リスクの発生源を捉えた設計
    • 省令や法改正にともなって、計算ロジックを自動生成してアップデートする
    • 近所のバス時刻表を画像でとってきて、自動的にアップデートする
    • 仮説さえ明らかなら、自動的に最適化するデザイン
  • エージェント型のAI駆動型のインタフェース
    • 外部サービスのAPI変更があっても、目的さえ伝えておけば、自動実行
  • 自動アップデート付きのフレームワーク
    • 安全に自動アップデートするエージェント機能のあるフレームワーク

目的と手段の階梯の手段から順番に自動化されていく

まとめ

まとめ

  • 社会を取り巻く「目に見えない力を生み出す構造」=アーキテクチャ。
  • アーキテクチャを構成する様々なパースペクティブ
    • ビジネスモデル、組織構造、プロジェクト、アーキテクチャ。
  • 技術的負債ではなくソフトウェアコントローラビリティの喪失が問題
  • 技術選定/アーキテクチャ設計は難しいが、「失敗」をリカバリーできる体制やチーム、組織を作り上げることが最も大事。
  • 意思決定の経験を正しく学びに繋げ、将来のチームメイトに配慮する。
まとめ

ご清聴ありがとうございました

  • 本日中にスライド公開予定
  • 皆さんの実践例もぜひ共有ください
\n
\n
\n `.split(/\n\s*/).join(""),this.wrapper=this.shadowRoot.querySelector(`div[${e}]`)??void 0;const t=this.svg;this.svg=this.wrapper?.querySelector(`svg[${i}]`)??void 0,this.svg!==t&&(this.svgComputedStyle=this.svg?window.getComputedStyle(this.svg):void 0),this.container=this.svg?.querySelector(`span[${n}]`)??void 0,this.observe()}disconnectedCallback(){this.svg=void 0,this.svgComputedStyle=void 0,this.wrapper=void 0,this.container=void 0,this.observe()}attributeChangedCallback(){this.observe()}flushSvgDisplay(){const{svg:t}=this;t&&(t.style.display="inline",requestAnimationFrame((()=>{t.style.display=""})))}observe(){this.containerObserver.disconnect(),this.wrapperObserver.disconnect(),this.wrapper&&this.wrapperObserver.observe(this.wrapper),this.container&&this.containerObserver.observe(this.container),this.svgComputedStyle&&this.observeSVGStyle(this.svgComputedStyle)}observeSVGStyle(t){const e=()=>{const i=(()=>{const e=t.getPropertyValue("--preserve-aspect-ratio");if(e)return e.trim();return`x${(({textAlign:t,direction:e})=>{if(t.endsWith("left"))return"Min";if(t.endsWith("right"))return"Max";if("start"===t||"end"===t){let i="rtl"===e;return"end"===t&&(i=!i),i?"Max":"Min"}return"Mid"})(t)}YMid meet`})();i!==this.svgPreserveAspectRatio&&(this.svgPreserveAspectRatio=i,this.updateSVGRect()),t===this.svgComputedStyle&&requestAnimationFrame(e)};e()}updateSVGRect(){let t=Math.ceil(this.containerSize?.width??0);const e=Math.ceil(this.containerSize?.height??0);void 0!==this.dataset.downscaleOnly&&(t=Math.max(t,this.wrapperSize?.width??0));const i=this.svg?.querySelector(":scope > foreignObject");if(i?.setAttribute("width",`${t}`),i?.setAttribute("height",`${e}`),this.svg&&(this.svg.setAttribute("viewBox",`0 0 ${t} ${e}`),this.svg.setAttribute("preserveAspectRatio",this.svgPreserveAspectRatio),this.svg.style.height=t<=0||e<=0?"0":""),this.container){const t=this.svgPreserveAspectRatio.toLowerCase();this.container.style.marginLeft=t.startsWith("xmid")||t.startsWith("xmax")?"auto":"0",this.container.style.marginRight=t.startsWith("xmi")?"auto":"0"}}}const r=(t,{attrs:e={},style:i})=>class extends t{constructor(...t){super(...t);for(const[t,i]of Object.entries(e))this.hasAttribute(t)||this.setAttribute(t,i);this._shadow()}static get observedAttributes(){return["data-auto-scaling"]}connectedCallback(){this._update()}attributeChangedCallback(){this._update()}_shadow(){if(!this.shadowRoot)try{this.attachShadow({mode:"open"})}catch(t){if(!(t instanceof Error&&"NotSupportedError"===t.name))throw t}return this.shadowRoot}_update(){const t=this._shadow();if(t){const e=i?``:"";let n="";const{autoScaling:s}=this.dataset;if(void 0!==s){n=`${n}`}t.innerHTML=e+n}}};let o;const a=Symbol();let l;const c="marpitSVGPolyfill:setZoomFactor,",d=Symbol(),h=Symbol();const g=()=>{const t="Apple Computer, Inc."===navigator.vendor,e=t?[u]:[],i={then:e=>(t?(async()=>{if(void 0===l){const t=document.createElement("canvas");t.width=10,t.height=10;const e=t.getContext("2d"),i=new Image(10,10),n=new Promise((t=>{i.addEventListener("load",(()=>t()))}));i.crossOrigin="anonymous",i.src="data:image/svg+xml;charset=utf8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2210%22%20height%3D%2210%22%20viewBox%3D%220%200%201%201%22%3E%3CforeignObject%20width%3D%221%22%20height%3D%221%22%20requiredExtensions%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxhtml%22%3E%3Cdiv%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxhtml%22%20style%3D%22width%3A%201px%3B%20height%3A%201px%3B%20background%3A%20red%3B%20position%3A%20relative%22%3E%3C%2Fdiv%3E%3C%2FforeignObject%3E%3C%2Fsvg%3E",await n,e.drawImage(i,0,0),l=e.getImageData(5,5,1,1).data[3]<128}return l})().then((t=>{null==e||e(t?[u]:[])})):null==e||e([]),i)};return Object.assign(e,i)};let p,m;function u(t){const e="object"==typeof t&&t.target||document,i="object"==typeof t?t.zoom:t;window[h]||(Object.defineProperty(window,h,{configurable:!0,value:!0}),document.body.style.zoom=1.0001,document.body.offsetHeight,document.body.style.zoom=1,window.addEventListener("message",(({data:t,origin:e})=>{if(e===window.origin)try{if(t&&"string"==typeof t&&t.startsWith(c)){const[,e]=t.split(","),i=Number.parseFloat(e);Number.isNaN(i)||(m=i)}}catch(t){console.error(t)}})));let n=!1;Array.from(e.querySelectorAll("svg[data-marpit-svg]"),(t=>{var e,s,r,o;t.style.transform||(t.style.transform="translateZ(0)");const a=i||m||t.currentScale||1;p!==a&&(p=a,n=a);const l=t.getBoundingClientRect(),{length:c}=t.children;for(let i=0;i{null==t||t.postMessage(`${c}${n}`,"null"===window.origin?"*":window.origin)}))}function v({once:t=!1,target:e=document}={}){const i=function(t=document){if(t[d])return t[d];let e=!0;const i=()=>{e=!1,delete t[d]};Object.defineProperty(t,d,{configurable:!0,value:i});let n=[],s=!1;(async()=>{try{n=await g()}finally{s=!0}})();const r=()=>{for(const e of n)e({target:t});s&&0===n.length||e&&window.requestAnimationFrame(r)};return r(),i}(e);return t?(i(),()=>{}):i}p=1,m=void 0;const w=Symbol(),b=(e=document)=>{if("undefined"==typeof window)throw new Error("Marp Core's browser script is valid only in browser context.");if(((e=document)=>{const i=window[a];i||customElements.define("marp-auto-scaling",s);for(const n of Object.keys(t)){const s=`marp-${n}`,a=t[n].proto();(o??(o=!!document.createElement("div",{is:"marp-auto-scaling"}).outerHTML.startsWith("
{t.outerHTML=t.outerHTML.replace(new RegExp(`^<${n}`,"i"),`<${s}`).replace(new RegExp(`${n}>$`,"i"),`${s}>`)})))}window[a]=!0})(e),e[w])return e[w];const i=v({target:e}),n=()=>{i(),delete e[w]},l=Object.assign(n,{cleanup:n,update:()=>b(e)});return Object.defineProperty(e,w,{configurable:!0,value:l}),l},y=document.currentScript;b(y?y.getRootNode():document)}();