From a89d3516da5fd942946f22cabd7c9588dc05795e Mon Sep 17 00:00:00 2001 From: ma91n Date: Thu, 11 Jun 2026 21:20:27 +0900 Subject: [PATCH] =?UTF-8?q?Mermaid.js=20Live=20Editor=20=E3=81=AETips=209?= =?UTF-8?q?=E9=81=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ..._Editor_\343\201\256Tips_9\351\201\270.md" | 252 ++++++++++++++++++ source/images/2026/20260612a/thumbnail.png | Bin 0 -> 3693 bytes source/images/2026/20260612a/top.png | Bin 0 -> 4855 bytes 3 files changed, 252 insertions(+) create mode 100644 "source/_posts/2026/20260612a_Mermaid_Live_Editor_\343\201\256Tips_9\351\201\270.md" create mode 100644 source/images/2026/20260612a/thumbnail.png create mode 100644 source/images/2026/20260612a/top.png diff --git "a/source/_posts/2026/20260612a_Mermaid_Live_Editor_\343\201\256Tips_9\351\201\270.md" "b/source/_posts/2026/20260612a_Mermaid_Live_Editor_\343\201\256Tips_9\351\201\270.md" new file mode 100644 index 00000000000..d66538d7feb --- /dev/null +++ "b/source/_posts/2026/20260612a_Mermaid_Live_Editor_\343\201\256Tips_9\351\201\270.md" @@ -0,0 +1,252 @@ +--- +title: "Mermaid Live Editor のTips 9選" +date: 2026/06/12 00:00:00 +postid: a +tag: + - mermaid.js +category: + - Programming +thumbnail: /images/2026/20260612a/thumbnail.png +author: 真野隼記 +lede: "Mermaid.js で図を書こうと Mermaid Live Editor を開いたはいいものの、思いの外色々なボタンがあって機能を使いこなせない!と感じている人も多いのではないでしょうか。そんな人に役立つかもしれない知識を、Tipsという形で9つまとめました。" +--- + + + +# はじめに + +TIG(Technology Innovation Group)の真野です。 + +Mermaid.js で図を書こうと [Mermaid Live Editor](https://mermaid.live/) を開いたはいいものの、思いの外色々なボタンがあって機能を使いこなせない!と感じている人も多いのではないでしょうか。 + +そんな人に役立つかもしれない知識を、Tipsという形で9つまとめました。 + +## Mermaid.js とは? + +[Mermaid.js](https://mermaid.js.org/) はテキスト DSL から SVG で図を描画する JavaScript ライブラリです。2014年公開時点ではフローチャートとシーケンス図の2種類しかありませんでした。今ではフローチャート、シーケンス図、ER 図など、v11 時点で30種類近いダイアグラムに対応しています([ちなみに名前は『リトル・マーメイド』から取った](https://github.com/mermaid-js/mermaid/issues/1904#issuecomment-787065874)そうです)。 + +2022年2月に [GitHub が Markdown の Mermaid ネイティブサポート](https://github.blog/developer-skills/github/include-diagrams-markdown-files-mermaid/) を発表してから一気に広まった印象があり、現在は GitHub・GitLab・Notion などが標準対応しています。クライアントサイド JS 単独で動く身軽さと相まって、Diagrams as Code の中心的存在です。 + +同じく「図をテキストで書く」系としては [PlantUML](https://plantuml.com/) が先行しています。PlantUML は Java ベースで開発されていて、配置図・タイミング図・ユースケース図など UML 記号の網羅性が高いのが特徴です。ただしレンダリングにサーバサイド環境を要する分、GitHub や社内 Wiki にそのまま貼って読ませる気軽さは Mermaid の方がある、という棲み分けかなと思います。フューチャーでも過去に [PlantUML 用のカラーテーマ(toy / vibrant / mars)を自作して公式テーマに採用された](https://future-architect.github.io/articles/20211108a/) 経緯があり、社内では Mermaid.js も PlantUML もよく使われています。 + +## Mermaid Live Editor とは? + +[Mermaid Live Editor](https://mermaid.live/) は、Mermaid コードを書くとリアルタイムでプレビューしてくれる公式ブラウザ IDE です。ログイン不要で、開けばすぐ使えます。 + +画面構成は以下のとおり。 + +- 左ペイン:エディタ(`Code` / `Config` / `History` の3タブ) +- 右ペイン:プレビュー(`Diagram` / `Actions` タブ) +- 図のコードは URL に埋め込まれるため、URL を共有すれば同じ図が他人の環境で開ける + +裏側は VS Code と同じ [Monaco Editor](https://microsoft.github.io/monaco-editor/) ベースで、`Config` タブは独立した Monaco インスタンスです。これが後述するショートカット系Tipsに効いてきます。 + +# エディタを効率化する + +## 1. VS Code のショートカットがそのまま使える + +Live Editor のエディタは VS Code と同じ [Monaco Editor](https://microsoft.github.io/monaco-editor/) ベースなので、VS Code の感覚で使えるショートカットがそのまま効きます。個人的にヘビロテしているのは次の3つです。 + +| ショートカット | 動作 | +|---|---| +| `Ctrl + Alt + ↑/↓`(macOS は `Cmd + Alt + ↑/↓`) | マルチカーソル編集(縦方向に行追加) | +| `Shift + Alt + →/←` | 括弧 (`[]` / `()` / `{}`) 内のラベルを一気に選択 | +| `Ctrl + F` / `Cmd + F` | 正規表現対応の検索・置換 | + +ガントチャートで全タスクの期間を後ろ倒しにしたい時や、シーケンス図で参加者名を一括リネームしたい時にマルチカーソルが効きます。クラス図の属性名リファクタでは、正規表現置換(例:`private string (\w+)Name` → `private string $1_name`)が刺さります。「マウスに手を伸ばさない編集」が図面の編集にもそのまま効くのは、地味ですが効果が大きいです。 + +## 2. Config タブでスタイルを本体コードから隔離する + +Live Editor の左ペイン `Config` タブに JSON を書くと、[`theme` / `themeVariables`](https://mermaid.js.org/config/theming.html) といったスタイル設定を、コード本体の [frontmatter](https://mermaid.js.org/config/configuration.html#frontmatter-config) とは分離してプレビューに反映できます。 + +```json +{ + "theme": "forest", + "themeVariables": { + "primaryColor": "#ffefd5" + } +} +``` + +コード本体はこのままの素の状態で動きます。 + +````c +flowchart LR + A[開始] --> B[処理] --> C[終了] +```` + +frontmatter に `config:` を書くのと見た目の結果は同じです。 + +- コード本体と一緒に持ち回りたい → frontmatter に書く。移植性が高まる +- Live Editor 内だけで良い → Config タブに書く。コード本体をスリムに見せることができる + +ちなみに、`config` を変更してもURLは反映されるので、単にMermaid Live Editorで閉じてやり取りする場合はどちらを使っても大差ないです。こだわりがなければ、私は移植性が高いfrontmatter記述が良いと思いますが、どうでしょうか? + +## 3. 時計アイコンで履歴パネルを開きスナップショット保存 + +画面上部の GitHub アイコンの隣にある白黒の🕓️アイコンをクリックすると、履歴パネルが開きます。`Save Current State` を押すと現在の編集状態がスナップショットとして残り、後から一覧から選んで戻せます。 + +大きな編集をするときは、`Save Current State` でスナップショットを残すか、Live Editor を別タブで開いてそちらで試すのがお勧めです。元タブの URL(`#pako:...`)にその時点のコードが保持されているので、別タブの試行が失敗しても元タブに戻ればすぐやり直せます。`Save Current State` の保存先はブラウザの `localStorage` なので、別PC・別ブラウザには引き継がれない点には注意です。 + +同じ履歴パネルに `Save diagram` ボタンもありますが、こちらは Mermaid Chart のクラウドに保存するもので、[Mermaid Chart](https://www.mermaidchart.com/) アカウントへのログインが必要です。長期保管したいバージョンや環境を跨いで残したいバージョンは、ログインの上 `Save diagram` を使うか、GitHub 等の外部リポジトリで別途管理する運用になります。 + +# 見た目を整える + +## 4. ダークモードでの見え方を気軽に確認する + +Live Editor のプレビューエリア右下(白塗りの☀マーク / 🌜️マーク)には、背景をライト/ダークに切り替えるアイコンがあります。 + +Tip 2 のように `themeVariables` で独自スタイルを当てた時は、両モードで確認するクセをつけておくのが安全です。ライトモードでは視認性が良くなったが、ダークモードでは文字が読みにくいといったことも多いためです。特に技術ブログなど、外部公開系はどちらでも読めるようにしておくと、読者に優しいです。 + +## 5. スクラッチモードを Live Editor の外でも使う + +Live Editor のプレビューエリアの下部に、図を手書き風に描画してくれる `Sketch` モードの切替ボタン(✏️のようなボタン)があります。手書き風の方が頭に入りやすい気がするので、よく使いたくなります。 + +ただし Live Editor 上で `Sketch` を有効にしただけでは、コードを他ツールに貼り付けても手書き風は再現されません。`Sketch` はプレビュー側の描画オプションとして効いているだけで、コード本体には何も書き込まれないためです。 + +GitHub / Qiita / 自社サイトなどで同じ見た目を再現したい場合は、frontmatter の `config.look` に `handDrawn` を明示します。 + +```mermaid +--- +config: + look: handDrawn +--- +flowchart LR + A[開始] --> B[処理] --> C[終了] +``` + +```c +--- +config: + look: handDrawn +--- +flowchart LR + A[開始] --> B[処理] --> C[終了] +``` + +[`look: handDrawn`](https://mermaid.js.org/intro/syntax-reference.html#selecting-diagram-looks) は Mermaid v11 でサポートされた設定で、[Rough.js](https://roughjs.com/) ベースの揺れた線で図が描画されます。Live Editor の `Sketch` ボタンをオンにした時と同じ見た目が、コードブロックを貼り付けた先でも再現されるようになります。 + +# 共有・公開のTips + +## 6. 実は読み取り専用ビューを作れる + +Live Editor の共有URLには、実は2種類あります。 + +- `https://mermaid.live/edit#pako:...`:エディタUI付きで開く(デフォルト) +- `https://mermaid.live/view#pako:...`:プレビューだけの読み取り専用ビュー + +`#pako:...` 部分のハッシュは同一なので、URL のパスを `edit` / `view` で書き換えるだけで切り替わります。`edit` はエディタUI付きで編集可能、`view` は読み取り専用でレンダリング済みの図だけが表示されます。 + +`Share` ボタンから取得できるのは `edit` 系 URL のみで、`view` URL は UI 上には出てきません。コピーした URL のパス部分を手動で `view` に書き換える必要があります。 + +## 7. URL ハッシュの正体は pako + URL-safe base64 + +共有URLの `#pako:...` の正体を追っておきます。Live Editor の[serde.ts](https://github.com/mermaid-js/mermaid-live-editor/blob/develop/src/lib/util/serde.ts) を読むと、以下の処理が行われています。 + +1. 図のコードと設定を JSON 化 +2. [pako](https://github.com/nodeca/pako) で deflate 圧縮(level 9) +3. URL-safe base64 化(`+` → `-`、`/` → `_`) +4. 先頭に `pako:` プレフィックスを付ける + +これが分かると、Live Editor の UI を使わずに共有URLをプログラム生成できます。Python なら標準ライブラリだけで書けます。 + +```python +import base64 +import json +import zlib + +state = { + "code": "flowchart LR\n A[開始] --> B[処理] --> C[終了]", + "mermaid": '{"theme": "default"}', + "autoSync": True, + "updateDiagram": True, +} +compressed = zlib.compress(json.dumps(state).encode(), 9) +encoded = base64.urlsafe_b64encode(compressed).decode().rstrip("=") +print(f"https://mermaid.live/view#pako:{encoded}") +``` + +社内ツールで CSV → 図 → Live Editor URL という一括変換パイプラインを組もうと思えば組めそうです。pakoってなんだろう思ってましたが、ライブラリ名だったとは。 + +# Sample Diagrams を覗く + +## 8. Sample Diagrams にある ZenUML とは? + +Live Editor 上部の `Sample Diagrams` ドロップダウンを開くと、フローチャートやシーケンス図などに並んで `ZenUML` という見慣れない選択肢が入っています。個人的に以前から気になっていたので、この機会に中身を覗いてみました。 + +[ZenUML](https://zenuml.com/) は Mermaid v10 から統合されたシーケンス図専用の別 DSL で、標準の [`sequenceDiagram`](https://mermaid.js.org/syntax/sequenceDiagram.html) と並ぶ選択肢として Live Editor に同梱されています([公式ドキュメントの ZenUML ページ](https://mermaid.js.org/syntax/zenuml.html))。コードの1行目を `zenuml` にするだけで切り替わります。 + +標準 `sequenceDiagram`: + +```text +sequenceDiagram + Client->>API: POST /order + API->>DB: INSERT order + DB-->>API: ok + alt stock > 0 + API->>Queue: publish + API-->>Client: 201 Created + else + API-->>Client: 409 Conflict + end +``` + +ZenUML: + +```text +zenuml + title 注文フロー + Client->API.createOrder() { + API->DB.insert() + if (stock > 0) { + API->Queue.publish() + return 201 + } else { + return 409 + } + } +``` + +標準のシーケンス図が素直に上から下へ流れる記法なのに対し、ZenUML は Java / C# の関数呼び出しに近い中括弧ベースで、条件分岐・並列処理のネストが中に折り畳まれる形になります。`alt ... else ... end` で縦に伸びていく標準記法より、深いネストの構造が把握しやすい気がします。`while` / `par` / `try-catch`、`@Async` / `@Starter` などのアノテーションもあって、非同期フローの表現力でも ZenUML が優位です。 + +ただし現時点では大きな落とし穴があります。(※2026年5月時点)手元で試した限り、GitHub Markdown も Qiita も ZenUML コードブロックを描画できませんでした(各プラットフォームが内蔵する Mermaid レンダラーが ZenUML 統合のバージョンにまだ追いついていないのが原因のようです)。Mermaid 最大の旨味である「コードブロックをそのまま貼って読ませる」気軽さが失われるので、現時点では ZenUML の採用は見送り、標準の `sequenceDiagram` を使うのが無難、というのが実際に試してみての結論です。 + +# セキュアに使う + +## 9. Actions タブの Export 系ボタンは外部サービスに図コードを送信している + +`Actions` タブには `Copy Image` / `PNG` / `SVG` / `PDF` / `Copy Markdown` といった便利なボタンが並んでいます。Mermaid にネイティブ対応していない社内 Wiki やメール本文に図を貼りたい時に刺さる機能ですが、実際には Live Editor 本体ではなく外部サービスの [mermaid.ink](https://mermaid.ink/) や [Kroki](https://kroki.io/) にコードを送信してサーバサイドでレンダリングしています。 + +```mermaid +flowchart LR + User(("👤
ユーザー")) + subgraph browser["ブラウザ内(編集・プレビューはここで完結)"] + Editor[Live Editor] + end + subgraph external["外部サーバ"] + Ink[mermaid.ink / Kroki] + end + User -->|①編集・プレビュー| Editor + User -->|②Export ボタン押下| Editor + Editor -->|③図コードを送信| Ink + Ink -->|④画像 or 画像URL| Editor + Editor -->|⑤ダウンロード / クリップボード| User +``` + +プレビューしているだけならブラウザ内で完結していますが、Export ボタンを押した瞬間にコードが外に出る、という構造です。`Copy Markdown` はクリップボードに以下のような形を返してくれます。画像 URL をクリックすると Live Editor の編集画面に戻れる気の利いた作りで、Mermaid 非対応の Wiki・メールに貼るぶんには便利です。 + +```markdown +[![](https://mermaid.ink/img/pako:eNp...)](https://mermaid.live/edit#pako:eNp...) +``` + +便利な反面、社外秘の情報を扱うなど固くしたい場合は、これらのボタンを押さないといったチーム方針も考えられます。逆に技術ブログなど最初から公開前提の図であれば、mermaid.ink の URL にクエリパラメータを足して画像フォーマットや解像度を調整することもできます。パラメータの詳細は [mermaid.ink の README](https://github.com/jihchi/mermaid.ink) を参照してください。 + +完全に閉じた環境で図を画像化したい場合は、CLI の `mmdc`([mermaid-cli](https://github.com/mermaid-js/mermaid-cli))をローカルで回すのが現実的です。 + +おまけで、[Mermaid Chart](https://www.mermaidchart.com/) アカウント(無料)でログインすると、シンタックスエラー時にプレビューエリアに `Fix with AI` ボタンが表示され、LLM に修正案を返してもらえる機能も使えます。GeminiやClaudeなどに直してもらう人が多いと思いますので、利用したいモチベーションは低いかと思いますが、これも Mermaid Chart の LLM 基盤にコードを送信する仕組みです。そのため、Export 系と同じく社外秘の図では使わない方針が固いでしょう。 + +# おわりに + +毎日のように開いている Live Editor ですが、改めて整理してみると意外と触れていない機能がまだまだある、というのが書き終えての率直な感想です。 + +特に外部データ送信については、よく考えればその通りなのですが、きちんと考えたことはなかったので調べる過程で勉強になりました。 diff --git a/source/images/2026/20260612a/thumbnail.png b/source/images/2026/20260612a/thumbnail.png new file mode 100644 index 0000000000000000000000000000000000000000..396fb0385424a7a46392631a4ec499b56cd51001 GIT binary patch literal 3693 zcmc&%XH-+!77oEsLWfYKPm~&vCP6v~D7|9>0w$0ILP@9rM5Kly&VYqbqKtqDQbLK; zNFPNYlup1a%G`#aw~=d68mT%FGgfTh6z06@Ub z*4iBa;Lu>pR30w&IP>HIKl{ZI?SB3&fHo$(%2tjASvpw)08M#(f1p8Zoj1bPI~o8G z>_2)q#8vH6*b}nwp2!%alcP}}G5i!7Lkz&4iVu%qM*{#R=J65ez))PcT*a z!01s?#A8fV5c*EqP7zkvV7%?+D6Ge2XV1XPp@D`N6>~EIut~fTJ3}}&2CWz$9!7{Z ziZ_M+nb?ReADOkFW+qV>oRPcrxxXUVnkh6mCMLp2ODire?o^!KDPmNRmX4vJp_aC; zmaeWQJ3=!$fe?d^*Ca%r_$z@mHaaj09}$Bm5)_XTq63JrF{aSiSUkoEhsNm#U@-cc z0cbsprj8B1bl~^e_hcI%jloIswqX%E#bw|Ef=j{)+}SAzDWsEuB-^N05(X zBbO*VmW|@5q?wM%pZ@=_nP?pW`8Qx@|FE#v%9j4g%n?ohWEV?dQyRzSPUChF9{|8l zw6nJKjQ8K1kIOHZl6(5`gJxo(A8FOLB^8weveZttK4Gg(Dbm%6l(lq{m6H|FcFQiG zbkpb)7E=j00Y#mtc5{WeYUtSBuXf{6yf#^>!D4lN8C3`p+2a8>ZzPU&jR)a^26qy( zjuR91Oy8L*iGG%mSA;I5R?o9Xbr2;x-YQiI`q~whlWhP&LYD;ouci(~p1qyGODCO_ z&-5lj%W{u>&s@LD<6)F?GpgD_KP>NDO7>T|919I#lhkj4`CJI5+G!oog`zZoz52pbPQ;bLuFZ$1H%?{Ei#N7N!M9S% zMRyYCC6G-L*I;Ef@{qTdP{F2ZUifTJjPy->bxmrseKjpzjL|=Ip8B%eBlP_Ymr)ye zk33N${3&|nLFbDJ3A~gLtUQ+HomelJ zzw0t^i)i5hx`1rn9&ZQ?S!cQg8m*{GUDm0)ddy#*yUQiT$@pHm(M~C;@_8e+@ath` z6yWxEPTcF~`)Hda1Cs|dQV|4+zGltzsPS3nMF$$ysyNDUI2`hKF{oO8HZ4g7$$BWRl{-fAs79oBj=?{T!V{(LnxnZwwg>7kDR6(t1M z^P&4r7G1uT^yCJDdfKl)=^fVYmIsQgDUx+a7Dgt{?TaB}3{H=emvkA@-JOsySY{}9 zU%B0OSKtP$=$w%+sF5Y*WF z6Xy4Rgxjk#*Er|VWP3KIJ7?;&nlBDSep_zbcAoLZr9mC3q_Yi#?N!hBF9vAvu5!`p zx@ox!&mhRMTnlwx7BynwJC(hKh;R5deToRK9uC|qE$v&-BK=`nX3&uOv(fFLHhEVz z_B8L?jF1XHUY9}=&UZb-*~yqzAh<9BEsD{f6N!?XXvMUULLyRtu&^6E_uU&m=`lpR z3!hrPDP2)pxvvL=#>9vG+Ln4+a#TMuMIRT$XFMsdfw5E*nKft>#^U zfhc@Hrbox%B|3~yY%2W=AxPO3p1Es-%W*w?v3c#H{}rK6)Y*DbAcz7Jjnv!rr#@l_ z8q51EEBtUTy^D?bPS&n&^NSn_9l6)hYE2>oN5nrCd3)?XfispU)`BK*AgLhfi_MEl zFI>)O25j?MBCdzCzJygTDhi@Fyn^)mjlZhjGW;4Gzw~8$cA6_|SoSt%*ik4x^15H7 ziycVAxA-fg<+63^^3BH?s}k^K%;<+2_UgMQe-h~D-d-lrRSJbl{lm7PyD<~T!5W3u z6|O!UJ92k#VH3BxqQAJs<^PTFL|l8LYNCSf7x{u|P!^jyul|!es^bBc!?6h8*15ij z<~Dfv=)qV_!ocg;MU>{j#74S8-mEz94d96WM=8&#J_m=5Yt)0ils-BQcJ&ceyH$r=P10(IWPTDm3{(0s=QM%fBa5G zZ5cNlC(og=GSPUS226O zZ7SUog~fsGSDG*_-r1!M449-^qpx^wiCDP&T_R#Gc3gi&?VbF?N8afM@x9%Mj?KN* z2**Uaul-RjZ`RrNcZSup78t>(M^ZNNw&58d3Sl^R0Q;sM_dQ&`jup^aFQLNDDDm@I zD3{e?2ph>k)J*5db-xzP4A>aGA;QBBG`GwDXlkZl1cIc&o@Eslc6MEw?mqaHV=(S? z7M%b1!noZKVlGrUXU$W#D&Z4;IBHNHyVZPcg#E?KMcVIcO-}ab?`+mkOMNl$)sYt# zjCBaoEZb((G4fJpX4@a4ow3?GL%wbGQs>M${9e5hkIV;-NNRpUuS!c94A9zDX9)zNxIlMB-f#N~7hb8Y3{~z0eJKIL#7;XD>D22H z)0RUwLr5}T&p4I_l2F1Q)Eaed2y+|7S67b}bv&cts$g5>DhaD^7dq*~!r(eb(cF^r zyA==mh*dLF8%+Unci<38L;9)kjhcAJ)PkJON9l3q*~aHJmhJmVUlw#C_|H-);-jC0JtuUl5OQJK6m(-ee$;- zPWYn>Mj^;q8vEcU^bummD|X71c_U*%^kN{4Wpg5*%6UsxA>~(-!Mtd}S({EkfP`tR2g-xaHF%{Ai0lI`0<1E9gIUne7eVV+z4I_o_PZP;5 z@L=im6re-*O==*?bjB?N(XXFeZ1{`AEo+-prAs;1%pcywq%cJPZhsF`+ExTaIW3&m z*Q`$pjlXF(lt z)_7Red$S8FA|_0m@u~ADspLqK#wc){j9SQrGK7C|GG?}y*qVYU8{(63d~Fh}f(S@~ zg|C9!ti!Kdcvb0CpYwZH8XQW(Bdpid8t<3!Gs+W2z0UKT*Ez5EdA}apSebAmg^>UNZZp%1 zb^yR362{5#`*EAavGbe5+L;)F+5ypJh&kkEU}*qAed^)8>j;SF3^u)r1%T({?;F+= z^uh;#BgtkL4IJ*e|C-v(byz6s+1NvDZWd;8qN9eV2F3mwT`6B0slUP#OEJeBOsjxtpVaDU`Qt#7eKMeAmO5isT3c3EZ3)|_|eVxvPvv*P`1B!#fHuSRdg3;t?8G%xtaDt)4fnTH1Hsk+L6I ze4$%S9B;noP83`)-}LRKFJw&8@;d^ubqQV9&IDZexw*gL@lVa@R*k#iBR==m{vDi1H z0-~=p(goQ{M1?MG6xO-PIZY`YYz&zuGJT*RLf5lR48xF)(Cb^BQmPs2ZPy}ynmBi- zY9!2jSpJ#h(TNO|g)rXK{O3_oABw0YD`cDjT}a5cGvvX34mrpq`M(($`-&Z_U!|LL zWc`$eh95)GCP`VIjhx7!;AN*;oen6-tNU5)v@S|DN^^d7U;maXd&|MovQKnL0D^NXIzZ z#%)crbm0>gjTOwr=6veHu4YQL%x)jt3O@N8kxQ0QPTo)mS{pLL;(L-!p)B_?XTZARYM5{7r;{kd50BGNZ&lqh z({-9z3v5G0_?IgxrAL2#B#7|ruds?>NYj1StQ)(|R1XX*qdQaK`5EHNjGvX%A6DTt zEc|>8?YtNDgOr_MymHu7WJ>K~%R)8df<{#;eAsV!sq4FcxOogAMemEZJ-#Ouvfiz- z_4Ab1zF&``TT7&u-?{|it+dWWRCjn7=aqwoSsvD5vp~ctW7vuFF*$`zUt=bs3Mx~V zF00SE=Z@G7_Qb7NPyM1^xNY97{!tK#%gae9#MDEcXs}$v{GTOG<8+abdwB&nmahcC z7CueD#uXA%;b*I~`O(eMn>TgRj$CG6x?XZeV^KK#j5hJZ{nlF^Xf2^^ec0FYwQd)7 zGzGTMP=&jflMmz&`DNnU5X0PI5#xf!rlB-@4p#F?(q~G-JoXHHMum&S$eYSfezZT` zuTg7G)qX@`9`5*Mfhp%xLgI=O3$NWtWq#+C)|wfot?p^tYP_~aG1sVThASt3lucHo z%j!4UfNhlpT4UVYk6DA=)d#Vk9sAuSX&SqGO;Znr9Xs#HhQr?^!r!1=GdPPVNqWtN zoiF9Q%GDzReSV2GMs}$ z<-nnhCvQj$zoc}^&wZd{mb(mC^ks#vKaufsyLvyoE=-3JRc@v~KJgrb1~uJHgw5+# zPI_Ke9?qi?2HYCElLS%^U*LXC$$8ubTi~d=)kiu?(dP@bDs-z{VXLCy7vUuv%RbXj z{vJcML*g7-L2^v_b>`kwH?@1}{KcNqEuB`dzJ)Yo7s+U}9XWpBp z%6HVu+h@&x+j2)JFYp%7baA2w%8%h^U+JQpb|bOh_!l30PZ|(g}O9na5la;erWB{sBtCg0uHCGN z+KZ(O@|ig5+TWWO>1o2Vb=`@>h_*y!AJfNVUjGB(>2B{nki1mph+0$-ACD6Xe@a7Z|`j1G?jpKB4P@z{#|N+B)!@=vr)RW${15~of8p%j~C|c*Gti%oZz=)#Hz0b6bWO7 zBJMM>Wq7T%E3>N{|Cqo$^<%7#k(PM`lzr{070GF&b*Y;QKktz-G^eO{J4im^X#>Hn}>cfz9Qz zO4XmS2e&P*ZvXjft&&U62JAFg*vf=0m-W^Ec;6H{P57dBC`*YMNwcKSbZ6nGKB@~R zzOV)A7BNsTdRSXk9uQ#w7<~&En5S^Bwc~dG7y}1%S7?T<7>^gAwae+DRBRtmQ+>AXL zHBm=fuv0-bSa;edKNVBa8}(-Kw*&w{l#Z0Kte%42iglSMJ}&BH)12~pRUq|u|Z(2c-KX53WqyCmO*(` zh}`Wqq_2D-uN@CrXE%Ws(z*LRA+W^$z%WfEqYRj&!m;kgOAVSM2{lkPyVTB+PK7{9OCouFvaP+>25+N z*`8B05sn)iStJ(*OxY&x#}~5b62U!^b~US7rB3gZf3bhO2=l!7jCw96M~f@n z#n(k5faQG%4U$LR>1u>DY8^@cxmcm`iXNX1#T1#+L4A-!+IZw}zWQ4K?O0_mL2#+M zK9>knC75APu#|-%{9GTU;}#}0K~*Op%p$W>QLdi(Xw*GwrVImlUezDUx>zCSMa z7hK=i_m99gv8?-)UgJw8656krIoaYi8qf#@*CAET8;T)4O6Q)1%8$A>)c1+VJ%Q_M zR&Dn#-XKi2k?tjPsjao6P%*A_KMaZu0w$^YIl@g-WlW3Wh@!LXc$vX{$Cpb%noLJY zZ~-}|WnNh5^41$`k%uv9;z%G%$k|#qHaBQo4Q5wA=R6jaz8s_ZI_HaoKjg^K&j=R! zjrNe%8>b6;(H3j%V|JcfCg0G&!Mw3z(|N#S^=UYHJ(`7~EG7N@9M~97WQdQc&%q}; z#>IAe3$$ohJ0qoXy}uLT`lG4~zFyVs)I=?~%K*VO@7MjG<-q3fYlPU^SRkgypkR0E zU}@U(9=n4WB3>9T7&a31d`67>^+II|bvbBx+LUri(pM1NtR}%k8e6@~ie62fjtdhf zFiRcLV8kK7wpzP$vsmk#OYc}y*oMP2v-}PucQH4p6PyfMyK&CGHEc3d>(Gm1NFbg! zhVm#}d72usxb=WE$ggSw!?8hyPRZB}Z!Y(FwM%h}bW-}kEFVLIos+IZY~P9dAH>eg z6E;P*M%2pnwDn;)k=Mo@`tppC#XKsnwGCJ|i?Mp5)*^Mo0zoi!DVr1g|rh|1( z1UT?{5}EGclRxsWao0LG0w`HhG75@=dj^BCE5y*Gi~`OPK}hQR#BO|^r+lueKJ{hE zIv)afSgvMe6Pu;{AMI|`g}G*kaEu5;Qq{$UcM%j%VK1v9!t2gi6cTjy<&bwSOuYLn zX8o~`@wxRAA~SAQ8VXJg5uZ(OHM;4%JAmmRMq!2lFXW#y^obG|4Xp}c9N#Ykv-P*k zy5HlI>YB@MqOUgCb~j=7*rCpAwh7w!T8U!LM))%3RR*_iIV6IbKhf18eUD<|p2SWv zJbtE6?a6L%s#YVTM28vbYyb2B=Pd}@)#~kIJG;f)S;V@r5Y};RXi=gxg;a3EU|bi+ z3GP0H$J3utsWigW+~`4Jhp9va1`C29Xzmf>F~R;zzAV50bf88xuk#>Y>z~Nt`AKy) zE}|{qFbGb9-=0>SZ$8A;Sq}ITIK`->$nZ3p1~F)`r;x;lLkR-Ivn}T0j1;Y2Mq!WR zijHKa2z&=BO^%dIGOiNiXa}wezgQUFW};W=Y~Za!Xyvb zW2vlcisTA5a3@^hH8~OJK8I{E3f-MWY>w593|$W7m=%CVbJPLx3NWh&k)p%dGz$ zD`{R^0R0}s^Qmn29i{g%+k7VnKzo;~#BHOxwxjWWXmF^k-sx%3;XlgtemfR#D+s^| e