[{"data":1,"prerenderedAt":15195},["ShallowReactive",2],{"article:\u002Farticles\u002F2026\u002Facquire-multiple-resource-locks-in-consistent-order":3,"related-articles:\u002Farticles\u002F2026\u002Facquire-multiple-resource-locks-in-consistent-order":528,"search:articles":8350,"search:books":14455},{"id":4,"title":5,"body":6,"description":516,"extension":517,"meta":518,"navigation":261,"path":519,"publishDate":520,"published":261,"seo":521,"stem":522,"tags":523,"thumbnail":525,"updated":526,"__hash__":527},"articles\u002Farticles\u002F2026\u002Facquire-multiple-resource-locks-in-consistent-order.md","複数リソースをロックするときは、取得順序までそろえる",{"type":7,"value":8,"toc":502},"minimark",[9,13,21,24,27,31,34,37,80,83,138,145,148,157,160,163,174,177,180,183,188,194,198,201,207,210,213,219,222,228,231,234,238,241,338,345,352,355,362,365,369,372,378,385,388,394,397,400,403,407,410,413,418,421,424,431,438,441,444,447,450,454,457,460,463,466,469,488,495,498],[10,11,12],"p",{},"こんにちは、Yuriです。",[10,14,15,16,20],{},"最近、複数のリソースをロックする処理では、「どのデータをロックするか」だけでなく、",[17,18,19],"strong",{},"「どの順番でロックするか」も重要","だと知りました。",[10,22,23],{},"たとえば、API・バッチ・Webhookが同じデータを更新する場合です。それぞれの処理でロックを取っていても、取得する順番が異なると、互いに相手のロックが解放されるのを待つ状況が起こりえます。",[10,25,26],{},"この記事では、その仕組みと、「リソースの種類ごとの順序」「同じ種類の中でのID順」をそろえる考え方を整理します。具体例にはPostgreSQLの行ロックを使います。",[28,29,30],"h2",{"id":30},"ロックしていても処理が進まなくなる理由",[10,32,33],{},"ここでは、注文と在庫を更新する架空のシステムを考えます。",[10,35,36],{},"APIでは注文を確認してから在庫を更新し、バッチでは在庫を確認してから注文を更新するとします。業務の流れに合わせて、そのままロックを取得すると次の順番になります。",[38,39,40,56],"table",{},[41,42,43],"thead",{},[44,45,46,50,53],"tr",{},[47,48,49],"th",{},"処理",[47,51,52],{},"最初にロックする行",[47,54,55],{},"次にロックする行",[57,58,59,71],"tbody",{},[44,60,61,65,68],{},[62,63,64],"td",{},"API",[62,66,67],{},"注文ID=10",[62,69,70],{},"在庫ID=20",[44,72,73,76,78],{},[62,74,75],{},"バッチ",[62,77,70],{},[62,79,67],{},[10,81,82],{},"それぞれ単独で実行すれば問題なく終わっても、同時に実行すると次の状況が起こりえます。",[38,84,85,96],{},[41,86,87],{},[44,88,89,92,94],{},[47,90,91],{},"順番",[47,93,64],{},[47,95,75],{},[57,97,98,108,118,128],{},[44,99,100,103,106],{},[62,101,102],{},"1",[62,104,105],{},"注文ID=10のロックを取得",[62,107],{},[44,109,110,113,115],{},[62,111,112],{},"2",[62,114],{},[62,116,117],{},"在庫ID=20のロックを取得",[44,119,120,123,126],{},[62,121,122],{},"3",[62,124,125],{},"在庫ID=20をロックしようとして待機",[62,127],{},[44,129,130,133,135],{},[62,131,132],{},"4",[62,134],{},[62,136,137],{},"注文ID=10をロックしようとして待機",[10,139,140,141,144],{},"APIが待っている在庫をバッチが持ち、バッチが待っている注文をAPIが持っています。このように待ち関係が循環する状態が",[17,142,143],{},"デッドロック","です。",[10,146,147],{},"PostgreSQLではデッドロックを検出すると、関係するトランザクションのうち1つを中止します。つまり、DBが検出してくれても、アプリケーションの処理がすべて成功するわけではありません。",[10,149,150],{},[151,152,156],"a",{"href":153,"rel":154},"https:\u002F\u002Fwww.postgresql.org\u002Fdocs\u002F18\u002Fexplicit-locking.html#LOCKING-DEADLOCKS",[155],"nofollow","PostgreSQL公式ドキュメント：デッドロック",[28,158,159],{"id":159},"すべての処理で同じ取得順序を使う",[10,161,162],{},"この例では、APIもバッチもWebhookも、次の順序でロックするルールにします。",[164,165,171],"pre",{"className":166,"code":168,"language":169,"meta":170},[167],"language-text","注文 → 在庫\n","text","",[172,173,168],"code",{"__ignoreMap":170},[10,175,176],{},"先ほどと同じ行に対してAPIが注文のロックを先に取得した場合、バッチは最初の注文のロックで待ちます。バッチはまだ在庫をロックしていないため、APIは在庫のロックを取得して処理を進められます。",[10,178,179],{},"APIがコミットしてロックを解放したあと、バッチが続けて処理します。待機そのものは発生しますが、先ほどのような待ち関係の循環は作られません。",[10,181,182],{},"PostgreSQLの公式ドキュメントでも、複数の対象をロックする際は、すべてのアプリケーションで一貫した順序を使うことがデッドロック対策として挙げられています。",[10,184,185],{},[151,186,156],{"href":153,"rel":187},[155],[10,189,190,191,144],{},"「注文から取得する」こと自体に特別な意味があるわけではありません。大切なのは、",[17,192,193],{},"同じリソースを扱うすべての処理が、同じルールを守ること",[28,195,197],{"id":196},"同じ種類のリソースではid順もそろえる","同じ種類のリソースではID順もそろえる",[10,199,200],{},"種類ごとの順序だけでは、まだ足りません。1つの処理で複数の在庫をロックする場合を考えます。",[164,202,205],{"className":203,"code":204,"language":169,"meta":170},[167],"API:     在庫ID=20 → 在庫ID=30\nWebhook: 在庫ID=30 → 在庫ID=20\n",[172,206,204],{"__ignoreMap":170},[10,208,209],{},"この場合も、互いに最初のロックを取得するとデッドロックになりえます。",[10,211,212],{},"そこで、同じ種類のリソースではIDの昇順でロックするルールを追加します。",[164,214,217],{"className":215,"code":216,"language":169,"meta":170},[167],"1. 注文をID昇順でロックする\n2. 在庫をID昇順でロックする\n\n例:\n注文ID=10 → 注文ID=11 → 在庫ID=20 → 在庫ID=30\n",[172,218,216],{"__ignoreMap":170},[10,220,221],{},"考え方としては、各リソースに次の比較キーを持たせるイメージです。",[164,223,226],{"className":224,"code":225,"language":169,"meta":170},[167],"（リソースの種類に付けた順位, ID）\n\n注文ID=10: (1, 10)\n注文ID=11: (1, 11)\n在庫ID=20: (2, 20)\n在庫ID=30: (2, 30)\n",[172,227,225],{"__ignoreMap":170},[10,229,230],{},"このキーで全体の順序を決め、必要な対象を前から取得します。同じIDでも、注文と在庫は別のリソースとして扱います。",[10,232,233],{},"ID昇順は、共通の順序を作るための方法の1つです。UUIDや複合キーを使う場合も、処理ごとに比較結果が変わらないルールを決めます。",[28,235,237],{"id":236},"postgresqlで取得順序を明示する例","PostgreSQLで取得順序を明示する例",[10,239,240],{},"以下は、必要な注文IDと在庫IDが事前に分かっている場合の、ロック取得部分の例です。各IDは主キーで、対象の行は存在するものとします。",[164,242,246],{"className":243,"code":244,"language":245,"meta":170,"style":170},"language-sql shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","BEGIN;\n\n-- まず注文をID昇順でロックする\nSELECT * FROM orders WHERE id = 10 FOR UPDATE;\nSELECT * FROM orders WHERE id = 11 FOR UPDATE;\n\n-- 次に在庫をID昇順でロックする\nSELECT * FROM inventories WHERE id = 20 FOR UPDATE;\nSELECT * FROM inventories WHERE id = 30 FOR UPDATE;\n\n-- ロック取得後の値で、注文状態や在庫数を確認する\n-- 条件を満たす場合に、必要なUPDATEを実行する\n-- 条件を満たさない場合はROLLBACKする\n\nCOMMIT;\n","sql",[172,247,248,256,263,269,275,281,286,292,298,304,309,315,321,327,332],{"__ignoreMap":170},[249,250,253],"span",{"class":251,"line":252},"line",1,[249,254,255],{},"BEGIN;\n",[249,257,259],{"class":251,"line":258},2,[249,260,262],{"emptyLinePlaceholder":261},true,"\n",[249,264,266],{"class":251,"line":265},3,[249,267,268],{},"-- まず注文をID昇順でロックする\n",[249,270,272],{"class":251,"line":271},4,[249,273,274],{},"SELECT * FROM orders WHERE id = 10 FOR UPDATE;\n",[249,276,278],{"class":251,"line":277},5,[249,279,280],{},"SELECT * FROM orders WHERE id = 11 FOR UPDATE;\n",[249,282,284],{"class":251,"line":283},6,[249,285,262],{"emptyLinePlaceholder":261},[249,287,289],{"class":251,"line":288},7,[249,290,291],{},"-- 次に在庫をID昇順でロックする\n",[249,293,295],{"class":251,"line":294},8,[249,296,297],{},"SELECT * FROM inventories WHERE id = 20 FOR UPDATE;\n",[249,299,301],{"class":251,"line":300},9,[249,302,303],{},"SELECT * FROM inventories WHERE id = 30 FOR UPDATE;\n",[249,305,307],{"class":251,"line":306},10,[249,308,262],{"emptyLinePlaceholder":261},[249,310,312],{"class":251,"line":311},11,[249,313,314],{},"-- ロック取得後の値で、注文状態や在庫数を確認する\n",[249,316,318],{"class":251,"line":317},12,[249,319,320],{},"-- 条件を満たす場合に、必要なUPDATEを実行する\n",[249,322,324],{"class":251,"line":323},13,[249,325,326],{},"-- 条件を満たさない場合はROLLBACKする\n",[249,328,330],{"class":251,"line":329},14,[249,331,262],{"emptyLinePlaceholder":261},[249,333,335],{"class":251,"line":334},15,[249,336,337],{},"COMMIT;\n",[10,339,340,341,344],{},"説明のため、1行ずつ順番に取得しています。",[172,342,343],{},"FOR UPDATE"," の行ロックは通常トランザクション終了まで保持されるため、取得と更新を同じトランザクション内で行います。",[10,346,347],{},[151,348,351],{"href":349,"rel":350},"https:\u002F\u002Fwww.postgresql.org\u002Fdocs\u002F18\u002Fexplicit-locking.html#LOCKING-ROWS",[155],"PostgreSQL公式ドキュメント：行レベルロック",[10,353,354],{},"実装では、対象IDの重複を取り除き、決めた順番に並べてから、逐次ロックを取得する流れにします。入力の配列順やWebhookのペイロード内の順序を、そのまま取得順序にしないことがポイントです。",[10,356,357,358,361],{},"また、",[172,359,360],{},"WHERE id IN (20, 30)"," のようにIDを並べるだけでは、ロックの取得順序を指定したことにはなりません。複数行をまとめて取得する実装では、使用するDBの仕様と、ORMが発行するSQLを確認する必要があります。",[10,363,364],{},"この例は既存行を対象にしています。検索結果が0件の場合、存在しない行をロックできたことにはならないため、存在確認や新規作成の競合対策は別途必要です。",[28,366,368],{"id":367},"ルールは関数単位ではなくトランザクション全体で守る","ルールは関数単位ではなく、トランザクション全体で守る",[10,370,371],{},"共通のロック取得関数を作っても、呼び出す前に別のロックを取得していると順序が崩れます。",[164,373,376],{"className":374,"code":375,"language":169,"meta":170},[167],"Webhookの処理:\n  在庫ID=30を更新する\n  → 共通関数を呼ぶ\n  → 注文ID=10をロックする\n  → 在庫ID=20をロックする\n",[172,377,375],{"__ignoreMap":170},[10,379,380,381,384],{},"共通関数の中が「注文 → 在庫」でも、トランザクション全体では「在庫 → 注文」になっています。明示的なロックだけでなく、",[172,382,383],{},"UPDATE"," によって取得する行ロックも含めて考えます。",[10,386,387],{},"バッチでも、1件ずつの処理が正しい順番だからといって安心はできません。",[164,389,392],{"className":390,"code":391,"language":169,"meta":170},[167],"1つのトランザクションで複数件を処理:\n  注文ID=10 → 在庫ID=20 → 注文ID=11 → 在庫ID=30\n",[172,393,391],{"__ignoreMap":170},[10,395,396],{},"この順番では、在庫のあとに再び注文を取得しています。全件を同じトランザクションで扱う必要があるなら、必要な注文を先に、次に必要な在庫をそれぞれID順で取得する設計にします。1件ごとにトランザクションを分けられるかは、業務上必要な原子性に合わせて判断します。",[10,398,399],{},"途中で追加のロック対象が判明する場合も同様です。すでに取得した対象より前の順番になるなら、そのまま取り足すとルールが崩れます。対象の決め方を見直すか、ロールバックして対象を再確認し、正しい順序で取得し直す設計が必要です。",[28,401,402],{"id":402},"取得順序以外にも考えること",[404,405,406],"h3",{"id":406},"ロックの強さを途中で変更する場合",[10,408,409],{},"取得するリソースが同じでも、複数の処理が共有ロックを持ってから、互いに競合する強いロックへ変更しようとすると、デッドロックになりえます。",[10,411,412],{},"更新が必要な対象には、最初からその処理で必要な強さのロックを取得することも考えます。リソースの順序だけでは、ロックの強さを変更する際の競合までは解決できません。",[10,414,415],{},[151,416,156],{"href":153,"rel":417},[155],[404,419,420],{"id":420},"失敗時はトランザクション全体を再実行する",[10,422,423],{},"取得順序を統一しても、ほかの更新経路や暗黙に取得されるロックまで含めて、デッドロックが絶対に起きないと言い切ることはできません。",[10,425,426,427,430],{},"PostgreSQLのデッドロックエラーはSQLSTATE ",[172,428,429],{},"40P01"," です。再試行する場合は、失敗したSQLだけでなく、読み取りや更新内容の判断を含めたトランザクション全体をやり直します。",[10,432,433],{},[151,434,437],{"href":435,"rel":436},"https:\u002F\u002Fwww.postgresql.org\u002Fdocs\u002F18\u002Fmvcc-serialization-failure-handling.html",[155],"PostgreSQL公式ドキュメント：失敗時の再試行",[10,439,440],{},"アプリケーション側では、再試行の回数に上限を設け、待ち時間を入れるなど、競合が続いたときの扱いも決めておきます。",[404,442,443],{"id":443},"ロックを持つ時間を短くする",[10,445,446],{},"ロックの順序をそろえても、競合する処理の待ち時間は残ります。",[10,448,449],{},"外部APIの応答待ちなどをロック取得後に挟むと、ほかの処理も長く待つことになります。ロック中に必要な確認・更新を整理し、トランザクションを長時間開いたままにしない設計にします。",[404,451,453],{"id":452},"webhookの重複処理は別に対策する","Webhookの重複処理は別に対策する",[10,455,456],{},"ロックを取得できるのは一度に1つの処理でも、同じイベントが順番に2回処理されることはあります。",[10,458,459],{},"そのため、ロックだけではWebhookの重複処理を防げません。イベントIDの一意制約や処理済み記録などを使い、重複の判定と業務データの更新を原子的に行う設計が必要です。",[10,461,462],{},"また、DBのロールバックでは外部APIへの送信は取り消せません。トランザクションを再試行するなら、外部への副作用が重複しないようにすることも別途考えます。",[28,464,465],{"id":465},"まとめ",[10,467,468],{},"複数リソースをロックするときは、ロックする対象に加えて、取得する順番を設計する必要があります。",[470,471,472,476,479,482,485],"ul",{},[473,474,475],"li",{},"リソースの種類ごとに取得順序を決める",[473,477,478],{},"同じ種類のリソースはID昇順など、共通のルールで並べる",[473,480,481],{},"API・バッチ・Webhookのすべてで同じルールを守る",[473,483,484],{},"関数の中だけでなく、トランザクション全体の取得順序を見る",[473,486,487],{},"リトライや重複処理への対策も用意する",[10,489,490,491,494],{},"今回学んだのは、",[17,492,493],{},"ロックの取得順序は、個別の処理ではなく、同じリソースを扱う処理全体で共有するルールになる","ということです。",[10,496,497],{},"新しいAPIやバッチを追加するときも、「この処理だけで正しく動くか」に加えて、「既存の処理と同時に動いても、ロックの順序がそろっているか」を確認していきたいと思います。",[499,500,501],"style",{},"html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":170,"searchDepth":258,"depth":258,"links":503},[504,505,506,507,508,509,515],{"id":30,"depth":258,"text":30},{"id":159,"depth":258,"text":159},{"id":196,"depth":258,"text":197},{"id":236,"depth":258,"text":237},{"id":367,"depth":258,"text":368},{"id":402,"depth":258,"text":402,"children":510},[511,512,513,514],{"id":406,"depth":265,"text":406},{"id":420,"depth":265,"text":420},{"id":443,"depth":265,"text":443},{"id":452,"depth":265,"text":453},{"id":465,"depth":258,"text":465},"API・バッチ・Webhookが同じデータを更新するとき、リソースの種類とIDでロックの取得順序を統一し、デッドロックを防ぐ考え方を整理します。","md",{},"\u002Farticles\u002F2026\u002Facquire-multiple-resource-locks-in-consistent-order","2026-09-18",{"title":5,"description":516},"articles\u002F2026\u002Facquire-multiple-resource-locks-in-consistent-order",[524],"PostgreSQL","\u002Fimages\u002Farticles\u002Facquire-multiple-resource-locks-in-consistent-order.png",null,"csz0VtK4hyp8-jB9XPeLrHNen-iE8sjaWXdCfCPl10k",[529,1238,1591,2485,3165,3779,4485,6133,6621,7108,7535,7926],{"id":530,"title":531,"body":532,"description":1226,"extension":517,"meta":1227,"navigation":261,"path":1228,"publishDate":1229,"published":261,"seo":1230,"stem":1231,"tags":1232,"thumbnail":1236,"updated":526,"__hash__":1237},"articles\u002Farticles\u002F2026\u002Frethinking-ai-development-workspace.md","AIと開発するために、改めて作業環境を見直してみた",{"type":7,"value":533,"toc":1211},[534,536,539,542,545,552,555,559,562,608,611,614,617,620,624,627,634,637,661,664,670,673,676,679,687,690,693,696,700,703,706,709,729,736,739,742,746,749,752,755,762,765,768,771,817,820,823,826,912,915,931,938,941,945,948,951,954,973,980,983,986,1010,1013,1016,1019,1023,1026,1039,1042,1048,1055,1066,1125,1132,1135,1149,1152,1158,1181,1184,1187,1190,1193,1196,1199,1202,1205,1208],[10,535,12],{},[10,537,538],{},"最近、普段使うエディターをZedへ乗り換えたり、AIエージェントとの開発の進め方を考えたりする中で、改めて自分の作業環境を見直してみました。",[10,540,541],{},"今回整理したかったのは、AIに何を任せ、自分はどこでコードを読み、どのタイミングで判断するのかということです。",[10,543,544],{},"Claude CodeとCodexを使うなら、それぞれの担当を決めたい。実装されたコードは、自分が読みやすいエディターで確認したい。ターミナルでも、今どのディレクトリとブランチにいるのかをすぐに把握したい。",[10,546,547,548,551],{},"こうした希望を整理して、",[17,549,550],{},"AGI CockpitでAIの作業を管理し、Zedを自分がコードを読む・確認する場所として使う","方針にしました。",[10,553,554],{},"この記事では、これから試していく開発の運用方針と、実際に設定したZedのターミナルについてまとめます。運用全体の効果はこれから確かめる段階ですが、まずは役割と作業場所を明確にするところから始めます。",[28,556,558],{"id":557},"aiと自分の担当を決める","AIと自分の担当を決める",[10,560,561],{},"今回の構成は、次の4つです。",[38,563,564,574],{},[41,565,566],{},[44,567,568,571],{},[47,569,570],{},"ツール",[47,572,573],{},"今回の担当",[57,575,576,584,592,600],{},[44,577,578,581],{},[62,579,580],{},"AGI Cockpit",[62,582,583],{},"AIエージェントへの依頼、タスクの切り替え、進捗確認",[44,585,586,589],{},[62,587,588],{},"Zed",[62,590,591],{},"自分がコードや差分を読み、軽微な修正や動作確認をする場所",[44,593,594,597],{},[62,595,596],{},"Claude Code",[62,598,599],{},"要件の整理、設計、実装後のレビュー",[44,601,602,605],{},[62,603,604],{},"Codex",[62,606,607],{},"設計に沿った実装、テスト、レビュー指摘の修正",[10,609,610],{},"この担当分けは、今回の自分の運用として決めたものです。それぞれのAIでできることを限定する意図はありません。",[10,612,613],{},"自分はTech Leadのような立場で、要件や設計の採否、変更範囲、最終的な品質を判断します。",[10,615,616],{},"たとえば設計の段階では、「今回の機能に対して複雑すぎないか」「既存の構成と合っているか」を確認する。実装後には、差分と動作を見て「依頼した内容になっているか」を確認する。AIのレビュー指摘についても、採用するかを自分で判断します。",[10,618,619],{},"AIへの依頼や進行管理はCockpitに集め、成果物を読む作業はZedに寄せる。この役割分担を、まずは試してみたいと考えています。",[28,621,623],{"id":622},"_1つの機能を同じ場所で順番に進める","1つの機能を、同じ場所で順番に進める",[10,625,626],{},"複数のAIを使うときに、先に決めておきたかったのが作業場所です。",[10,628,629,630,633],{},"今回の基本ルールは、",[17,631,632],{},"1機能につき1つのブランチ・1つの作業ディレクトリを使い、担当を順番に交代する","ことにしました。",[10,635,636],{},"たとえば一覧画面に絞り込み機能を追加するなら、次の流れを想定しています。",[638,639,640,643,646,649,652,655,658],"ol",{},[473,641,642],{},"Claude Codeが既存コードを調べ、設計と受け入れ条件を整理する",[473,644,645],{},"自分が設計を読み、変更方針を確認する",[473,647,648],{},"Codexが実装し、テストや必要な検証を行う",[473,650,651],{},"自分がZedで差分と動作を確認する",[473,653,654],{},"Claude Codeが設計と実装を照合してレビューする",[473,656,657],{},"Codexが採用した指摘を修正し、再度検証する",[473,659,660],{},"自分が最終確認し、コミットやPR、マージへ進める",[10,662,663],{},"この間、Claude CodeとCodexとZedは、同じ絶対パスのディレクトリを参照します。",[164,665,668],{"className":666,"code":667,"language":169,"meta":170},[167],"機能: 一覧の絞り込み\nブランチ: feature\u002Ffilter\n作業場所: ~\u002Fwork\u002Fproject\n\nClaude Code: 設計\n    ↓ 自分が確認\nCodex: 実装・テスト\n    ↓ 自分が確認\nClaude Code: レビュー\n    ↓\nCodex: 修正・再テスト\n    ↓ 自分が最終確認\n",[172,669,667],{"__ignoreMap":170},[10,671,672],{},"書き込みを行う担当は、常に1人または1エージェントにします。自分が少しだけ修正したい場合も、AIの編集が止まっている間に行う方針です。",[10,674,675],{},"レビュー工程では原則としてコードを変更せず、指摘を残して次の担当へ渡します。担当を交代するときは、前の処理が終わっていることと、現在のブランチ・未コミット差分を確認します。",[404,677,678],{"id":678},"worktreeは機能を分けたいときに使う",[10,680,681,682,686],{},"以前、",[151,683,685],{"href":684},"\u002Farticles\u002F2026\u002Fgit-worktree-with-docker-development","Git worktreeでDocker開発しようとしてハマった話","を書きました。そのときも、どのディレクトリのファイルを参照しているかが大事でした。",[10,688,689],{},"今回も、同じ機能を引き継ぐたびにAIごとのworktreeを作ると、作業場所の対応を管理する必要が増えます。まずは通常のcheckoutを使い、mainの作業場所と分けたい場合だけ、その機能用のworktreeを1つ用意する方針です。",[10,691,692],{},"同じ作業ディレクトリであれば、未コミットの変更も次の担当が読めます。節目のコミットは追跡のために残しつつ、AIへ担当を渡すたびにmergeやcherry-pickを挟む運用にはしません。",[10,694,695],{},"別の機能も同時に進めたくなったら、機能単位でworktreeを分ける。その場合も、1つの機能の中では同じ作業場所を共有します。",[28,697,699],{"id":698},"ファイルと一緒に判断の経緯も引き継ぐ","ファイルと一緒に、判断の経緯も引き継ぐ",[10,701,702],{},"同じファイルを読めても、前のAIとの会話まで自動的に伝わるわけではありません。",[10,704,705],{},"「どうしてこの設計にしたのか」「何を確認済みなのか」「どこがまだ終わっていないのか」は、別途伝える必要があります。",[10,707,708],{},"引き継ぎには、次の情報を残すことにしました。",[470,710,711,714,717,720,723,726],{},[473,712,713],{},"目的と受け入れ条件",[473,715,716],{},"作業ディレクトリとブランチ",[473,718,719],{},"設計判断と変更対象",[473,721,722],{},"現在の差分や基準となるコミット",[473,724,725],{},"実行したテストと結果",[473,727,728],{},"未解決事項と次の担当への依頼",[10,730,731,732,735],{},"必要に応じて ",[172,733,734],{},"docs\u002Ffeature-filter-handoff.md"," のようなメモにまとめ、次の担当に読むよう依頼します。",[10,737,738],{},"たとえば「実装できました」だけでは、次のレビューで何を基準にすればよいか分かりません。「空の検索結果を表示できること」「条件を解除すると全件に戻ること」といった受け入れ条件があれば、レビューの観点もそろえやすくなります。",[10,740,741],{},"最初は自分で工程を切り替え、引き継ぐ内容が安定してから自動化を検討したいと思っています。",[28,743,745],{"id":744},"zedは自分が読み続けられる環境にする","Zedは、自分が読み続けられる環境にする",[10,747,748],{},"Zedで重視したいのは、コードを読む・追う・確かめる作業のしやすさです。",[10,750,751],{},"落ち着いたOne Dark系の配色を基準に、文字サイズやファイルツリー、検索、定義ジャンプ、Gitの差分表示を整える方針にしました。言語支援についても、普段触るVueなどのファイルで使い勝手を確認していきます。",[10,753,754],{},"ターミナルもZed内を起点にし、動作確認やGit操作を行います。そこで気になったのが、現在のパスやブランチをもっと見やすくしたいということでした。",[10,756,757,758,761],{},"最初の構成案ではプロンプトの候補にStarshipを挙げていましたが、実際に設定したのは ",[17,759,760],{},"zsh + Powerlevel10k + Nerd Font"," です。",[10,763,764],{},"ここからは、その設定で確認できた内容を残します。",[28,766,767],{"id":767},"ターミナルの状態表示と入力を2行に分ける",[10,769,770],{},"今回のターミナルは、次の構成です。",[38,772,773,783],{},[41,774,775],{},[44,776,777,780],{},[47,778,779],{},"要素",[47,781,782],{},"役割",[57,784,785,793,801,809],{},[44,786,787,790],{},[62,788,789],{},"Zed Terminal",[62,791,792],{},"文字を表示し、入力を受け取る",[44,794,795,798],{},[62,796,797],{},"zsh",[62,799,800],{},"コマンドを解釈・実行する",[44,802,803,806],{},[62,804,805],{},"Powerlevel10k",[62,807,808],{},"パスやGit情報などのプロンプトを組み立てる",[44,810,811,814],{},[62,812,813],{},"MesloLGS Nerd Font Mono",[62,815,816],{},"文字とアイコンを描画する",[10,818,819],{},"Powerlevel10kのウィザードでは、色付きのブロックで情報を分けるRainbowスタイルを選びました。",[10,821,822],{},"特に取り入れたかったのは、上段にパスやGit情報などの状態を表示し、下段にコマンドを入力する2行構成です。状態表示が横に長くなっても、入力を始める位置が分かりやすくなります。",[10,824,825],{},"主な選択は、次のとおりです。",[38,827,828,838],{},[41,829,830],{},[44,831,832,835],{},[47,833,834],{},"項目",[47,836,837],{},"選択",[57,839,840,848,856,864,872,880,888,896,904],{},[44,841,842,845],{},[62,843,844],{},"スタイル",[62,846,847],{},"Rainbow",[44,849,850,853],{},[62,851,852],{},"文字セット",[62,854,855],{},"Unicode",[44,857,858,861],{},[62,859,860],{},"時刻",[62,862,863],{},"24時間表記",[44,865,866,869],{},[62,867,868],{},"区切り \u002F 終端",[62,870,871],{},"Angled \u002F Sharp",[44,873,874,877],{},[62,875,876],{},"高さ",[62,878,879],{},"Two lines",[44,881,882,885],{},[62,883,884],{},"接続線",[62,886,887],{},"Dotted、色はDark",[44,889,890,893],{},[62,891,892],{},"枠",[62,894,895],{},"No frame",[44,897,898,901],{},[62,899,900],{},"アイコン",[62,902,903],{},"Many icons",[44,905,906,909],{},[62,907,908],{},"補助語",[62,910,911],{},"Concise",[10,913,914],{},"ウィザードを開くコマンドは次のものです。",[164,916,919],{"className":917,"code":918,"language":797,"meta":170,"style":170},"language-zsh shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","p10k configure\n",[172,920,921],{"__ignoreMap":170},[249,922,923,927],{"class":251,"line":252},[249,924,926],{"class":925},"sBMFI","p10k",[249,928,930],{"class":929},"sfazB"," configure\n",[10,932,933,934,937],{},"再設定する場合は、手動で調整した ",[172,935,936],{},"~\u002F.p10k.zsh"," の控えを残してから行います。",[10,939,940],{},"実行済みのプロンプトを短くするTransient Promptについては、過去の出力にもパスやブランチを残す方向で考えています。ただし、手元の記録では最終的な選択まで確認できないため、ここでは好みとして書いておきます。",[28,942,944],{"id":943},"アイコンがになってしまった","アイコンが「?」になってしまった",[10,946,947],{},"設定でつまずいたのが、アイコンの表示でした。",[10,949,950],{},"Powerlineのdiamondは表示されるのに、Appleやフォルダ、ブランチ、時計のアイコンが「?」になってしまいました。",[10,952,953],{},"Nerd FontはHomebrewで追加していました。",[164,955,957],{"className":917,"code":956,"language":797,"meta":170,"style":170},"brew install --cask font-meslo-lg-nerd-font\n",[172,958,959],{"__ignoreMap":170},[249,960,961,964,967,970],{"class":251,"line":252},[249,962,963],{"class":925},"brew",[249,965,966],{"class":929}," install",[249,968,969],{"class":929}," --cask",[249,971,972],{"class":929}," font-meslo-lg-nerd-font\n",[10,974,975,976,979],{},"それでも表示されなかった原因は、",[17,977,978],{},"Zedに指定していたフォント名と、macOSに登録されていたFamily名が一致していなかったこと","でした。",[404,981,982],{"id":982},"プロンプトを通さずにアイコンを表示する",[10,984,985],{},"切り分けでは、問題が起きているZedのターミナルで、次のコマンドを実行しました。",[164,987,989],{"className":917,"code":988,"language":797,"meta":170,"style":170},"print -P '\\uf179  \\uf07c  \\uf126  \\uf017'\n",[172,990,991],{"__ignoreMap":170},[249,992,993,997,1000,1004,1007],{"class":251,"line":252},[249,994,996],{"class":995},"s2Zo4","print",[249,998,999],{"class":929}," -P",[249,1001,1003],{"class":1002},"sMK4o"," '",[249,1005,1006],{"class":929},"\\uf179  \\uf07c  \\uf126  \\uf017",[249,1008,1009],{"class":1002},"'\n",[10,1011,1012],{},"Apple・フォルダ・ブランチ・時計の4つのアイコンを直接表示するテストです。",[10,1014,1015],{},"プロンプトの配置を介さずに文字を表示すると、プロンプト側の設定を調べる前に、そもそもその文字を描画できているか確認できます。",[10,1017,1018],{},"ここで学んだのが、diamondが表示されるだけでは、使いたいアイコンまで表示できるとは判断できないということでした。実際に表示できていない文字で確認する必要があります。",[404,1020,1022],{"id":1021},"macosに登録されている名前を調べる","macOSに登録されている名前を調べる",[10,1024,1025],{},"フォント情報は、次のコマンドで確認しました。",[164,1027,1029],{"className":917,"code":1028,"language":797,"meta":170,"style":170},"system_profiler SPFontsDataType\n",[172,1030,1031],{"__ignoreMap":170},[249,1032,1033,1036],{"class":251,"line":252},[249,1034,1035],{"class":925},"system_profiler",[249,1037,1038],{"class":929}," SPFontsDataType\n",[10,1040,1041],{},"今回の出力には、次の情報がありました。",[164,1043,1046],{"className":1044,"code":1045,"language":169,"meta":170},[167],"Full Name: MesloLGS Nerd Font Mono Regular\nFamily: MesloLGS Nerd Font Mono\nValid: Yes\nEnabled: Yes\n",[172,1047,1045],{"__ignoreMap":170},[10,1049,1050,1051,1054],{},"フォントは存在し、有効になっていました。一方、Zed側では ",[172,1052,1053],{},"MesloLGS NF"," を指定していました。",[10,1056,1057,1058,1061,1062,1065],{},"そこで、Zedの ",[172,1059,1060],{},"settings.json"," にある既存の ",[172,1063,1064],{},"terminal"," 設定を、登録されたFamily名に合わせて更新しました。ベルの設定も含めると、次の形です。",[164,1067,1071],{"className":1068,"code":1069,"language":1070,"meta":170,"style":170},"language-json shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","{\n  \"terminal\": {\n    \"font_family\": \"MesloLGS Nerd Font Mono\"\n  }\n}\n","json",[172,1072,1073,1078,1095,1115,1120],{"__ignoreMap":170},[249,1074,1075],{"class":251,"line":252},[249,1076,1077],{"class":1002},"{\n",[249,1079,1080,1083,1086,1089,1092],{"class":251,"line":258},[249,1081,1082],{"class":1002},"  \"",[249,1084,1064],{"class":1085},"spNyl",[249,1087,1088],{"class":1002},"\"",[249,1090,1091],{"class":1002},":",[249,1093,1094],{"class":1002}," {\n",[249,1096,1097,1100,1103,1105,1107,1110,1112],{"class":251,"line":265},[249,1098,1099],{"class":1002},"    \"",[249,1101,1102],{"class":925},"font_family",[249,1104,1088],{"class":1002},[249,1106,1091],{"class":1002},[249,1108,1109],{"class":1002}," \"",[249,1111,813],{"class":929},[249,1113,1114],{"class":1002},"\"\n",[249,1116,1117],{"class":251,"line":271},[249,1118,1119],{"class":1002},"  }\n",[249,1121,1122],{"class":251,"line":277},[249,1123,1124],{"class":1002},"}\n",[10,1126,1127,1128,1131],{},"保存後にZedを ",[172,1129,1130],{},"⌘Q"," で完全終了し、再起動して新しいターミナルを開くと、アイコンが正常に表示されました。",[10,1133,1134],{},"このフォント名は今回の環境で確認できたものです。別の環境で設定する場合も、インストールしたフォントの登録情報を確認すると切り分けやすいと思います。",[10,1136,1137,1138,1141,1142,1145,1146,1148],{},"なお、途中で試した ",[172,1139,1140],{},"fc-list"," は、このMacでは ",[172,1143,1144],{},"command not found"," になりました。今回は追加でツールを導入せず、",[172,1147,1035],{}," で必要な情報を確認できました。",[404,1150,1151],{"id":1151},"表示とプロンプトの設定を分けて考える",[10,1153,1154,1155,1157],{},"今回確認した ",[172,1156,936],{}," のアイコンモードは、次の値でした。",[164,1159,1161],{"className":917,"code":1160,"language":797,"meta":170,"style":170},"typeset -g POWERLEVEL9K_MODE=nerdfont-complete\n",[172,1162,1163],{"__ignoreMap":170},[249,1164,1165,1168,1171,1175,1178],{"class":251,"line":252},[249,1166,1167],{"class":1085},"typeset",[249,1169,1170],{"class":929}," -g",[249,1172,1174],{"class":1173},"sTEyZ"," POWERLEVEL9K_MODE",[249,1176,1177],{"class":1002},"=",[249,1179,1180],{"class":1173},"nerdfont-complete\n",[10,1182,1183],{},"これはPowerlevel10k側の設定で、Zedが使用するフォントの指定とは別です。",[10,1185,1186],{},"プロンプトの並びや装飾はPowerlevel10k、実際に描画するフォントはZed。この担当を分けて考えると、次に表示が崩れたときも確認する場所を絞れそうです。",[28,1188,1189],{"id":1189},"必要になったものから追加していく",[10,1191,1192],{},"構成を考える中では、HermesやOrcaなども候補に挙がりました。ただ、今は自分で設計や差分を確認し、次の担当へ渡す運用から始めたいと考えています。",[10,1194,1195],{},"まずはCockpitとZedを使う方針に絞り、自動化をどこまで進めるかは、実際に引き継ぎを繰り返してから判断します。",[10,1197,1198],{},"ターミナルの補助ツールも同様です。Git操作を補いたくなったらlazygit、検索や移動に手間を感じたらfzfやzoxideなどを検討します。初期構成にすべてを入れる予定はありません。",[10,1200,1201],{},"今回、開発の進め方とターミナルの設定を一緒に見直してみて、どちらにも「今どこで、何をしているのか分かるようにしたい」という共通点があると感じました。",[10,1203,1204],{},"AIの作業では、担当・作業場所・引き継ぐ内容を明確にする。自分のターミナルでは、パスとブランチを見やすくする。",[10,1206,1207],{},"次は小さな1機能で、設計から実装、レビュー、修正までを一度通してみるつもりです。自分が判断しやすいか、引き継ぎに情報が足りているかを確かめながら、この環境を調整していきたいと思います。",[499,1209,1210],{},"html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}",{"title":170,"searchDepth":258,"depth":258,"links":1212},[1213,1214,1217,1218,1219,1220,1225],{"id":557,"depth":258,"text":558},{"id":622,"depth":258,"text":623,"children":1215},[1216],{"id":678,"depth":265,"text":678},{"id":698,"depth":258,"text":699},{"id":744,"depth":258,"text":745},{"id":767,"depth":258,"text":767},{"id":943,"depth":258,"text":944,"children":1221},[1222,1223,1224],{"id":982,"depth":265,"text":982},{"id":1021,"depth":265,"text":1022},{"id":1151,"depth":265,"text":1151},{"id":1189,"depth":258,"text":1189},"AGI Cockpit・Zed・Claude Code・Codexの役割分担と、同じ作業場所で順番に開発する運用を整理しました。ZedのターミナルをPowerlevel10kとNerd Fontで整えた際のつまずきも紹介します。",{},"\u002Farticles\u002F2026\u002Frethinking-ai-development-workspace","2026-09-21",{"title":531,"description":1226},"articles\u002F2026\u002Frethinking-ai-development-workspace",[1233,1234,588,1235],"開発環境","AI","ターミナル","\u002Fimages\u002Farticles\u002Frethinking-ai-development-workspace.png","x8IB3rPjh68WyjuVVyJx-T0ZP2fsQQM8f0Lu_dMAlds",{"id":4,"title":5,"body":1239,"description":516,"extension":517,"meta":1588,"navigation":261,"path":519,"publishDate":520,"published":261,"seo":1589,"stem":522,"tags":1590,"thumbnail":525,"updated":526,"__hash__":527},{"type":7,"value":1240,"toc":1574},[1241,1243,1247,1249,1251,1253,1255,1257,1287,1289,1335,1339,1341,1346,1348,1350,1355,1357,1359,1361,1366,1370,1372,1374,1379,1381,1383,1388,1390,1395,1397,1399,1401,1403,1467,1471,1476,1478,1482,1484,1486,1488,1493,1497,1499,1504,1506,1508,1510,1512,1514,1516,1521,1523,1525,1529,1534,1536,1538,1540,1542,1544,1546,1548,1550,1552,1554,1566,1570,1572],[10,1242,12],{},[10,1244,15,1245,20],{},[17,1246,19],{},[10,1248,23],{},[10,1250,26],{},[28,1252,30],{"id":30},[10,1254,33],{},[10,1256,36],{},[38,1258,1259,1269],{},[41,1260,1261],{},[44,1262,1263,1265,1267],{},[47,1264,49],{},[47,1266,52],{},[47,1268,55],{},[57,1270,1271,1279],{},[44,1272,1273,1275,1277],{},[62,1274,64],{},[62,1276,67],{},[62,1278,70],{},[44,1280,1281,1283,1285],{},[62,1282,75],{},[62,1284,70],{},[62,1286,67],{},[10,1288,82],{},[38,1290,1291,1301],{},[41,1292,1293],{},[44,1294,1295,1297,1299],{},[47,1296,91],{},[47,1298,64],{},[47,1300,75],{},[57,1302,1303,1311,1319,1327],{},[44,1304,1305,1307,1309],{},[62,1306,102],{},[62,1308,105],{},[62,1310],{},[44,1312,1313,1315,1317],{},[62,1314,112],{},[62,1316],{},[62,1318,117],{},[44,1320,1321,1323,1325],{},[62,1322,122],{},[62,1324,125],{},[62,1326],{},[44,1328,1329,1331,1333],{},[62,1330,132],{},[62,1332],{},[62,1334,137],{},[10,1336,140,1337,144],{},[17,1338,143],{},[10,1340,147],{},[10,1342,1343],{},[151,1344,156],{"href":153,"rel":1345},[155],[28,1347,159],{"id":159},[10,1349,162],{},[164,1351,1353],{"className":1352,"code":168,"language":169,"meta":170},[167],[172,1354,168],{"__ignoreMap":170},[10,1356,176],{},[10,1358,179],{},[10,1360,182],{},[10,1362,1363],{},[151,1364,156],{"href":153,"rel":1365},[155],[10,1367,190,1368,144],{},[17,1369,193],{},[28,1371,197],{"id":196},[10,1373,200],{},[164,1375,1377],{"className":1376,"code":204,"language":169,"meta":170},[167],[172,1378,204],{"__ignoreMap":170},[10,1380,209],{},[10,1382,212],{},[164,1384,1386],{"className":1385,"code":216,"language":169,"meta":170},[167],[172,1387,216],{"__ignoreMap":170},[10,1389,221],{},[164,1391,1393],{"className":1392,"code":225,"language":169,"meta":170},[167],[172,1394,225],{"__ignoreMap":170},[10,1396,230],{},[10,1398,233],{},[28,1400,237],{"id":236},[10,1402,240],{},[164,1404,1405],{"className":243,"code":244,"language":245,"meta":170,"style":170},[172,1406,1407,1411,1415,1419,1423,1427,1431,1435,1439,1443,1447,1451,1455,1459,1463],{"__ignoreMap":170},[249,1408,1409],{"class":251,"line":252},[249,1410,255],{},[249,1412,1413],{"class":251,"line":258},[249,1414,262],{"emptyLinePlaceholder":261},[249,1416,1417],{"class":251,"line":265},[249,1418,268],{},[249,1420,1421],{"class":251,"line":271},[249,1422,274],{},[249,1424,1425],{"class":251,"line":277},[249,1426,280],{},[249,1428,1429],{"class":251,"line":283},[249,1430,262],{"emptyLinePlaceholder":261},[249,1432,1433],{"class":251,"line":288},[249,1434,291],{},[249,1436,1437],{"class":251,"line":294},[249,1438,297],{},[249,1440,1441],{"class":251,"line":300},[249,1442,303],{},[249,1444,1445],{"class":251,"line":306},[249,1446,262],{"emptyLinePlaceholder":261},[249,1448,1449],{"class":251,"line":311},[249,1450,314],{},[249,1452,1453],{"class":251,"line":317},[249,1454,320],{},[249,1456,1457],{"class":251,"line":323},[249,1458,326],{},[249,1460,1461],{"class":251,"line":329},[249,1462,262],{"emptyLinePlaceholder":261},[249,1464,1465],{"class":251,"line":334},[249,1466,337],{},[10,1468,340,1469,344],{},[172,1470,343],{},[10,1472,1473],{},[151,1474,351],{"href":349,"rel":1475},[155],[10,1477,354],{},[10,1479,357,1480,361],{},[172,1481,360],{},[10,1483,364],{},[28,1485,368],{"id":367},[10,1487,371],{},[164,1489,1491],{"className":1490,"code":375,"language":169,"meta":170},[167],[172,1492,375],{"__ignoreMap":170},[10,1494,380,1495,384],{},[172,1496,383],{},[10,1498,387],{},[164,1500,1502],{"className":1501,"code":391,"language":169,"meta":170},[167],[172,1503,391],{"__ignoreMap":170},[10,1505,396],{},[10,1507,399],{},[28,1509,402],{"id":402},[404,1511,406],{"id":406},[10,1513,409],{},[10,1515,412],{},[10,1517,1518],{},[151,1519,156],{"href":153,"rel":1520},[155],[404,1522,420],{"id":420},[10,1524,423],{},[10,1526,426,1527,430],{},[172,1528,429],{},[10,1530,1531],{},[151,1532,437],{"href":435,"rel":1533},[155],[10,1535,440],{},[404,1537,443],{"id":443},[10,1539,446],{},[10,1541,449],{},[404,1543,453],{"id":452},[10,1545,456],{},[10,1547,459],{},[10,1549,462],{},[28,1551,465],{"id":465},[10,1553,468],{},[470,1555,1556,1558,1560,1562,1564],{},[473,1557,475],{},[473,1559,478],{},[473,1561,481],{},[473,1563,484],{},[473,1565,487],{},[10,1567,490,1568,494],{},[17,1569,493],{},[10,1571,497],{},[499,1573,501],{},{"title":170,"searchDepth":258,"depth":258,"links":1575},[1576,1577,1578,1579,1580,1581,1587],{"id":30,"depth":258,"text":30},{"id":159,"depth":258,"text":159},{"id":196,"depth":258,"text":197},{"id":236,"depth":258,"text":237},{"id":367,"depth":258,"text":368},{"id":402,"depth":258,"text":402,"children":1582},[1583,1584,1585,1586],{"id":406,"depth":265,"text":406},{"id":420,"depth":265,"text":420},{"id":443,"depth":265,"text":443},{"id":452,"depth":265,"text":453},{"id":465,"depth":258,"text":465},{},{"title":5,"description":516},[524],{"id":1592,"title":685,"body":1593,"description":2475,"extension":517,"meta":2476,"navigation":261,"path":684,"publishDate":2477,"published":261,"seo":2478,"stem":2479,"tags":2480,"thumbnail":2483,"updated":2477,"__hash__":2484},"articles\u002Farticles\u002F2026\u002Fgit-worktree-with-docker-development.md",{"type":7,"value":1594,"toc":2461},[1595,1597,1600,1603,1606,1609,1612,1615,1618,1622,1625,1628,1631,1638,1641,1652,1655,1659,1662,1669,1701,1704,1710,1713,1719,1726,1730,1737,1740,1807,1813,1838,1852,1858,1864,1871,1877,1888,1894,1897,1900,1906,1909,1913,1916,1943,1970,1976,1982,1988,1991,2045,2048,2082,2113,2116,2131,2135,2138,2144,2147,2169,2172,2197,2219,2222,2225,2229,2232,2235,2241,2244,2248,2251,2300,2307,2334,2337,2341,2344,2347,2350,2361,2364,2371,2374,2377,2427,2430,2433,2435,2438,2441,2444,2448,2451,2458],[10,1596,12],{},[10,1598,1599],{},"最近、普段使うエディターをZed Editorへ乗り換えました。",[10,1601,1602],{},"Zed Editorで新しいスレッドを作る際にWorktreeを作成する選択肢があり、複数のブランチを並行して開発するのに便利そうだったため試してみました。",[10,1604,1605],{},"ブランチを切り替えるたびに作業中の変更をstashする必要がなく、AIエージェントへ別の作業を任せる場合にも相性が良さそうだと考えたためです。",[10,1607,1608],{},"ところが、worktree側でコードを変更しても、すでに起動していたDockerコンテナーへ変更が反映されませんでした。",[10,1610,1611],{},"最初は「同じGitリポジトリなのだから、worktree側の変更もコンテナーから見えるだろう」と、なんとなく考えていました。",[10,1613,1614],{},"しかし、Gitから見たリポジトリの関係と、Dockerが見ているホスト上のディレクトリは別の話です。",[10,1616,1617],{},"今回は、Git worktreeとDocker Composeを組み合わせてハマった原因と、複数のworktreeで開発環境を動かす方法を整理します。",[28,1619,1621],{"id":1620},"git-worktreeを使おうと思った理由","Git worktreeを使おうと思った理由",[10,1623,1624],{},"きっかけは、Zed EditorでAIエージェントのスレッドを作るときに、Worktreeを利用できることを知ったことでした。",[10,1626,1627],{},"スレッドごとに別のworktreeで作業できれば、普段の作業を続けながら、AIエージェントには別ブランチの実装を任せられます。",[10,1629,1630],{},"通常、1つの作業ディレクトリで同時にcheckoutできるブランチは1つです。",[10,1632,1633,1634,1637],{},"別のブランチへ移るには ",[172,1635,1636],{},"git switch"," などで切り替えますが、未コミットの変更があると、そのままでは切り替えられない場合があります。",[10,1639,1640],{},"一方、開発中には次のように複数の作業を並行して進めたいことがあります。",[470,1642,1643,1646,1649],{},[473,1644,1645],{},"機能を実装しながら、別ブランチのレビュー指摘を修正する",[473,1647,1648],{},"長時間動く処理を待ちながら、別のタスクを進める",[473,1650,1651],{},"複数のAIエージェントに、それぞれ異なるブランチの作業を任せる",[10,1653,1654],{},"このような場面で、ブランチごとに独立した作業ディレクトリを用意できるGit worktreeが便利そうでした。",[28,1656,1658],{"id":1657},"git-worktreeとは","Git worktreeとは",[10,1660,1661],{},"Git worktreeは、1つのGitリポジトリに複数の作業ツリーを追加できる仕組みです。",[10,1663,1664,1665,1668],{},"たとえば、メインの作業ディレクトリと同じ階層に、",[172,1666,1667],{},"feature\u002Fsample"," ブランチ用のworktreeを作成します。",[164,1670,1674],{"className":1671,"code":1672,"language":1673,"meta":170,"style":170},"language-bash shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","cd sample-app\ngit worktree add ..\u002Fsample-app-feature feature\u002Fsample\n","bash",[172,1675,1676,1684],{"__ignoreMap":170},[249,1677,1678,1681],{"class":251,"line":252},[249,1679,1680],{"class":995},"cd",[249,1682,1683],{"class":929}," sample-app\n",[249,1685,1686,1689,1692,1695,1698],{"class":251,"line":258},[249,1687,1688],{"class":925},"git",[249,1690,1691],{"class":929}," worktree",[249,1693,1694],{"class":929}," add",[249,1696,1697],{"class":929}," ..\u002Fsample-app-feature",[249,1699,1700],{"class":929}," feature\u002Fsample\n",[10,1702,1703],{},"ホスト上には、次の2つの作業ディレクトリが存在する状態になります。",[164,1705,1708],{"className":1706,"code":1707,"language":169,"meta":170},[167],"projects\u002F\n├── sample-app\u002F          mainブランチの作業ディレクトリ\n└── sample-app-feature\u002F  feature\u002Fsampleブランチの作業ディレクトリ\n",[172,1709,1707],{"__ignoreMap":170},[10,1711,1712],{},"それぞれのディレクトリでは、異なるブランチのファイルを同時に開いて編集できます。Gitのオブジェクトや一部の管理情報は共有しますが、作業ツリー上のファイルはディレクトリごとに別々です。",[164,1714,1717],{"className":1715,"code":1716,"language":169,"meta":170},[167],"1つのGitリポジトリ\n├── worktree: sample-app\u002F          → main\n└── worktree: sample-app-feature\u002F  → feature\u002Fsample\n",[172,1718,1716],{"__ignoreMap":170},[10,1720,1721,1722,1725],{},"ここで重要なのは、",[17,1723,1724],{},"Git上では同じリポジトリに属していても、ホスト上では別のディレクトリである"," という点です。",[28,1727,1729],{"id":1728},"worktree側の変更がdockerへ反映されなかった","worktree側の変更がDockerへ反映されなかった",[10,1731,1732,1733,1736],{},"もともと ",[172,1734,1735],{},"sample-app\u002F"," では、Docker Composeを使ってアプリケーションを起動していました。",[10,1738,1739],{},"Composeファイルには、次のようなbind mountが設定されているものとします。",[164,1741,1745],{"className":1742,"code":1743,"language":1744,"meta":170,"style":170},"language-yaml shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","services:\n  app:\n    build: .\n    volumes:\n      - .:\u002Fapp\n    ports:\n      - \"3000:3000\"\n","yaml",[172,1746,1747,1756,1763,1774,1781,1789,1796],{"__ignoreMap":170},[249,1748,1749,1753],{"class":251,"line":252},[249,1750,1752],{"class":1751},"swJcz","services",[249,1754,1755],{"class":1002},":\n",[249,1757,1758,1761],{"class":251,"line":258},[249,1759,1760],{"class":1751},"  app",[249,1762,1755],{"class":1002},[249,1764,1765,1768,1770],{"class":251,"line":265},[249,1766,1767],{"class":1751},"    build",[249,1769,1091],{"class":1002},[249,1771,1773],{"class":1772},"sbssI"," .\n",[249,1775,1776,1779],{"class":251,"line":271},[249,1777,1778],{"class":1751},"    volumes",[249,1780,1755],{"class":1002},[249,1782,1783,1786],{"class":251,"line":277},[249,1784,1785],{"class":1002},"      -",[249,1787,1788],{"class":929}," .:\u002Fapp\n",[249,1790,1791,1794],{"class":251,"line":283},[249,1792,1793],{"class":1751},"    ports",[249,1795,1755],{"class":1002},[249,1797,1798,1800,1802,1805],{"class":251,"line":288},[249,1799,1785],{"class":1002},[249,1801,1109],{"class":1002},[249,1803,1804],{"class":929},"3000:3000",[249,1806,1114],{"class":1002},[10,1808,1809,1810,1812],{},"この状態で ",[172,1811,1735],{}," からコンテナーを起動します。",[164,1814,1816],{"className":1671,"code":1815,"language":1673,"meta":170,"style":170},"cd sample-app\ndocker compose up -d\n",[172,1817,1818,1824],{"__ignoreMap":170},[249,1819,1820,1822],{"class":251,"line":252},[249,1821,1680],{"class":995},[249,1823,1683],{"class":929},[249,1825,1826,1829,1832,1835],{"class":251,"line":258},[249,1827,1828],{"class":925},"docker",[249,1830,1831],{"class":929}," compose",[249,1833,1834],{"class":929}," up",[249,1836,1837],{"class":929}," -d\n",[10,1839,1840,1843,1844,1847,1848,1851],{},[172,1841,1842],{},".:\u002Fapp"," は、ホスト側の相対パス ",[172,1845,1846],{},"."," を、コンテナー側の ",[172,1849,1850],{},"\u002Fapp"," へbind mountする指定です。Composeファイル内の相対的なホストパスは、基本的にComposeファイルのあるディレクトリを基準に解決されます。",[10,1853,1854,1855,1857],{},"今回のコンテナーが見ていたのは、",[172,1856,1735],{}," のファイルでした。",[164,1859,1862],{"className":1860,"code":1861,"language":169,"meta":170},[167],"ホスト\nprojects\u002F\n├── sample-app\u002F ───────────────────┐\n│   └── src\u002F                       │ bind mount\n└── sample-app-feature\u002F            │\n    └── src\u002F                       ▼\n                              コンテナー\n                              \u002Fapp\u002F\n",[172,1863,1861],{"__ignoreMap":170},[10,1865,1866,1867,1870],{},"その後、",[172,1868,1869],{},"sample-app-feature\u002F"," でコードを変更しました。",[164,1872,1875],{"className":1873,"code":1874,"language":169,"meta":170},[167],"projects\u002Fsample-app-feature\u002Fsrc\u002F\n",[172,1876,1874],{"__ignoreMap":170},[10,1878,1879,1880,1882,1883,761,1885,1887],{},"しかし、既存コンテナーの ",[172,1881,1850],{}," が参照しているのは、引き続き ",[172,1884,1735],{},[172,1886,1869],{}," はmountされていないため、そこで行った変更はコンテナーへ反映されません。",[164,1889,1892],{"className":1890,"code":1891,"language":169,"meta":170},[167],"sample-app\u002Fsrc\u002F          → コンテナーの \u002Fapp から見える\nsample-app-feature\u002Fsrc\u002F  → コンテナーの \u002Fapp からは見えない\n",[172,1893,1891],{"__ignoreMap":170},[10,1895,1896],{},"Dockerは、その2つが同じGitリポジトリのworktreeかどうかを考慮しません。bind mountで指定されたホスト上のパスだけを参照します。",[10,1898,1899],{},"つまり、今回の原因は次の認識が抜けていたことでした。",[1901,1902,1903],"blockquote",{},[10,1904,1905],{},"Gitから見れば同じリポジトリの別worktree。でもDockerから見れば単なる別ディレクトリ。",[10,1907,1908],{},"「同じGitリポジトリ」と「同じディレクトリ」は別の話です。",[28,1910,1912],{"id":1911},"解決方法1-worktreeごとにdocker-composeを起動する","解決方法1: worktreeごとにDocker Composeを起動する",[10,1914,1915],{},"アプリケーションもDBもブランチごとに分けたい場合は、worktreeごとにDocker Composeを起動します。",[164,1917,1919],{"className":1671,"code":1918,"language":1673,"meta":170,"style":170},"cd sample-app\ndocker compose -p sample-app-main up -d\n",[172,1920,1921,1927],{"__ignoreMap":170},[249,1922,1923,1925],{"class":251,"line":252},[249,1924,1680],{"class":995},[249,1926,1683],{"class":929},[249,1928,1929,1931,1933,1936,1939,1941],{"class":251,"line":258},[249,1930,1828],{"class":925},[249,1932,1831],{"class":929},[249,1934,1935],{"class":929}," -p",[249,1937,1938],{"class":929}," sample-app-main",[249,1940,1834],{"class":929},[249,1942,1837],{"class":929},[164,1944,1946],{"className":1671,"code":1945,"language":1673,"meta":170,"style":170},"cd sample-app-feature\ndocker compose -p sample-app-feature up -d\n",[172,1947,1948,1955],{"__ignoreMap":170},[249,1949,1950,1952],{"class":251,"line":252},[249,1951,1680],{"class":995},[249,1953,1954],{"class":929}," sample-app-feature\n",[249,1956,1957,1959,1961,1963,1966,1968],{"class":251,"line":258},[249,1958,1828],{"class":925},[249,1960,1831],{"class":929},[249,1962,1935],{"class":929},[249,1964,1965],{"class":929}," sample-app-feature",[249,1967,1834],{"class":929},[249,1969,1837],{"class":929},[10,1971,1972,1975],{},[172,1973,1974],{},"-p"," でComposeのproject名を分けると、コンテナーやネットワーク、Composeが管理する名前付きVolumeを別のリソースとして扱えます。",[10,1977,1978,1979,1981],{},"各worktreeにあるComposeファイルの ",[172,1980,1842],{}," は、それぞれのworktreeをmountします。",[164,1983,1986],{"className":1984,"code":1985,"language":169,"meta":170},[167],"sample-app\u002F          → sample-app-mainのappコンテナー:\u002Fapp\nsample-app-feature\u002F  → sample-app-featureのappコンテナー:\u002Fapp\n",[172,1987,1985],{"__ignoreMap":170},[10,1989,1990],{},"ただし、同じホストポートは同時に利用できません。ポート番号を環境変数にして、worktreeごとに変更できるようにします。",[164,1992,1994],{"className":1742,"code":1993,"language":1744,"meta":170,"style":170},"services:\n  app:\n    build: .\n    volumes:\n      - .:\u002Fapp\n    ports:\n      - \"${APP_PORT:-3000}:3000\"\n",[172,1995,1996,2002,2008,2016,2022,2028,2034],{"__ignoreMap":170},[249,1997,1998,2000],{"class":251,"line":252},[249,1999,1752],{"class":1751},[249,2001,1755],{"class":1002},[249,2003,2004,2006],{"class":251,"line":258},[249,2005,1760],{"class":1751},[249,2007,1755],{"class":1002},[249,2009,2010,2012,2014],{"class":251,"line":265},[249,2011,1767],{"class":1751},[249,2013,1091],{"class":1002},[249,2015,1773],{"class":1772},[249,2017,2018,2020],{"class":251,"line":271},[249,2019,1778],{"class":1751},[249,2021,1755],{"class":1002},[249,2023,2024,2026],{"class":251,"line":277},[249,2025,1785],{"class":1002},[249,2027,1788],{"class":929},[249,2029,2030,2032],{"class":251,"line":283},[249,2031,1793],{"class":1751},[249,2033,1755],{"class":1002},[249,2035,2036,2038,2040,2043],{"class":251,"line":288},[249,2037,1785],{"class":1002},[249,2039,1109],{"class":1002},[249,2041,2042],{"class":929},"${APP_PORT:-3000}:3000",[249,2044,1114],{"class":1002},[10,2046,2047],{},"たとえば、メイン側では3000番、feature側では3001番を使用します。",[164,2049,2051],{"className":1671,"code":2050,"language":1673,"meta":170,"style":170},"# sample-app\u002F\nAPP_PORT=3000 docker compose -p sample-app-main up -d\n",[172,2052,2053,2059],{"__ignoreMap":170},[249,2054,2055],{"class":251,"line":252},[249,2056,2058],{"class":2057},"sHwdD","# sample-app\u002F\n",[249,2060,2061,2064,2066,2069,2072,2074,2076,2078,2080],{"class":251,"line":258},[249,2062,2063],{"class":1173},"APP_PORT",[249,2065,1177],{"class":1002},[249,2067,2068],{"class":929},"3000",[249,2070,2071],{"class":925}," docker",[249,2073,1831],{"class":929},[249,2075,1935],{"class":929},[249,2077,1938],{"class":929},[249,2079,1834],{"class":929},[249,2081,1837],{"class":929},[164,2083,2085],{"className":1671,"code":2084,"language":1673,"meta":170,"style":170},"# sample-app-feature\u002F\nAPP_PORT=3001 docker compose -p sample-app-feature up -d\n",[172,2086,2087,2092],{"__ignoreMap":170},[249,2088,2089],{"class":251,"line":252},[249,2090,2091],{"class":2057},"# sample-app-feature\u002F\n",[249,2093,2094,2096,2098,2101,2103,2105,2107,2109,2111],{"class":251,"line":258},[249,2095,2063],{"class":1173},[249,2097,1177],{"class":1002},[249,2099,2100],{"class":929},"3001",[249,2102,2071],{"class":925},[249,2104,1831],{"class":929},[249,2106,1935],{"class":929},[249,2108,1965],{"class":929},[249,2110,1834],{"class":929},[249,2112,1837],{"class":929},[10,2114,2115],{},"DBのポートもホストへ公開する場合は、同じように別の番号を割り当てる必要があります。アプリコンテナーからCompose内のDBへ接続するだけであれば、通常はDBのホスト側ポートを公開せず、サービス名とコンテナー側ポートで接続できます。",[2117,2118,2121],"article-callout",{"title":2119,"type":2120},"project名を省略した場合","note",[10,2122,2123,2124,2126,2127,2130],{},"Composeのproject名は、通常はComposeファイルのあるディレクトリ名などから決まります。worktreeのディレクトリ名が異なれば自動的に分かれる場合もありますが、",[172,2125,1974],{}," や ",[172,2128,2129],{},"COMPOSE_PROJECT_NAME"," で明示すると、どの環境のリソースなのか判断しやすくなります。",[28,2132,2134],{"id":2133},"解決方法2-共通サービスだけdockerで起動する","解決方法2: 共通サービスだけDockerで起動する",[10,2136,2137],{},"もう1つの方法は、DBやRedisなどの共通サービスだけをDockerで起動し、アプリケーションは各worktreeのホスト上で起動する構成です。",[164,2139,2142],{"className":2140,"code":2141,"language":169,"meta":170},[167],"sample-app\u002F          ── アプリをlocalhost:3000で起動 ─┐\n                                                       ├─ Docker上のDB、Redis\nsample-app-feature\u002F  ── アプリをlocalhost:3001で起動 ─┘\n",[172,2143,2141],{"__ignoreMap":170},[10,2145,2146],{},"たとえば、ComposeでDBとRedisだけを起動します。",[164,2148,2150],{"className":1671,"code":2149,"language":1673,"meta":170,"style":170},"docker compose up -d db redis\n",[172,2151,2152],{"__ignoreMap":170},[249,2153,2154,2156,2158,2160,2163,2166],{"class":251,"line":252},[249,2155,1828],{"class":925},[249,2157,1831],{"class":929},[249,2159,1834],{"class":929},[249,2161,2162],{"class":929}," -d",[249,2164,2165],{"class":929}," db",[249,2167,2168],{"class":929}," redis\n",[10,2170,2171],{},"その後、各worktreeでアプリケーションの開発サーバーを別のポートで起動します。",[164,2173,2175],{"className":1671,"code":2174,"language":1673,"meta":170,"style":170},"cd sample-app\npnpm dev --port 3000\n",[172,2176,2177,2183],{"__ignoreMap":170},[249,2178,2179,2181],{"class":251,"line":252},[249,2180,1680],{"class":995},[249,2182,1683],{"class":929},[249,2184,2185,2188,2191,2194],{"class":251,"line":258},[249,2186,2187],{"class":925},"pnpm",[249,2189,2190],{"class":929}," dev",[249,2192,2193],{"class":929}," --port",[249,2195,2196],{"class":1772}," 3000\n",[164,2198,2200],{"className":1671,"code":2199,"language":1673,"meta":170,"style":170},"cd sample-app-feature\npnpm dev --port 3001\n",[172,2201,2202,2208],{"__ignoreMap":170},[249,2203,2204,2206],{"class":251,"line":252},[249,2205,1680],{"class":995},[249,2207,1954],{"class":929},[249,2209,2210,2212,2214,2216],{"class":251,"line":258},[249,2211,2187],{"class":925},[249,2213,2190],{"class":929},[249,2215,2193],{"class":929},[249,2217,2218],{"class":1772}," 3001\n",[10,2220,2221],{},"アプリケーションの起動が軽く、言語やパッケージの実行環境をホスト側へ用意できる場合は、この構成のほうがシンプルです。",[10,2223,2224],{},"ただし、DBを共有すると、ブランチごとのmigrationが同じDBへ影響します。アプリケーションだけを分けても、データやschemaまで分離されるわけではありません。",[28,2226,2228],{"id":2227},"複数のworktreeでdockerを使うときの注意点","複数のworktreeでDockerを使うときの注意点",[404,2230,2231],{"id":2231},"ポートが競合する",[10,2233,2234],{},"複数のコンテナーや開発サーバーを同時に起動すると、同じホストポートを割り当てられません。",[164,2236,2239],{"className":2237,"code":2238,"language":169,"meta":170},[167],"Bind for 0.0.0.0:3000 failed: port is already allocated\n",[172,2240,2238],{"__ignoreMap":170},[10,2242,2243],{},"アプリ、DB、デバッガーなど、ホストへ公開しているポートをworktreeごとに整理する必要があります。",[404,2245,2247],{"id":2246},"docker-volumeが意図せず共有または分離される","Docker Volumeが意図せず共有または分離される",[10,2249,2250],{},"Composeが管理する名前付きVolumeは、基本的にproject名の影響を受けます。project名を分けると、DBのVolumeも別になるのが通常です。",[164,2252,2254],{"className":1742,"code":2253,"language":1744,"meta":170,"style":170},"services:\n  db:\n    volumes:\n      - db-data:\u002Fvar\u002Flib\u002Fmysql\n\nvolumes:\n  db-data:\n",[172,2255,2256,2262,2269,2275,2282,2286,2293],{"__ignoreMap":170},[249,2257,2258,2260],{"class":251,"line":252},[249,2259,1752],{"class":1751},[249,2261,1755],{"class":1002},[249,2263,2264,2267],{"class":251,"line":258},[249,2265,2266],{"class":1751},"  db",[249,2268,1755],{"class":1002},[249,2270,2271,2273],{"class":251,"line":265},[249,2272,1778],{"class":1751},[249,2274,1755],{"class":1002},[249,2276,2277,2279],{"class":251,"line":271},[249,2278,1785],{"class":1002},[249,2280,2281],{"class":929}," db-data:\u002Fvar\u002Flib\u002Fmysql\n",[249,2283,2284],{"class":251,"line":277},[249,2285,262],{"emptyLinePlaceholder":261},[249,2287,2288,2291],{"class":251,"line":283},[249,2289,2290],{"class":1751},"volumes",[249,2292,1755],{"class":1002},[249,2294,2295,2298],{"class":251,"line":288},[249,2296,2297],{"class":1751},"  db-data",[249,2299,1755],{"class":1002},[10,2301,2302,2303,2306],{},"一方、Volumeに ",[172,2304,2305],{},"name"," を明示している場合やexternal Volumeを使っている場合は、project名を分けても同じVolumeを参照できます。",[164,2308,2310],{"className":1742,"code":2309,"language":1744,"meta":170,"style":170},"volumes:\n  db-data:\n    name: sample-app-db-data\n",[172,2311,2312,2318,2324],{"__ignoreMap":170},[249,2313,2314,2316],{"class":251,"line":252},[249,2315,2290],{"class":1751},[249,2317,1755],{"class":1002},[249,2319,2320,2322],{"class":251,"line":258},[249,2321,2297],{"class":1751},[249,2323,1755],{"class":1002},[249,2325,2326,2329,2331],{"class":251,"line":265},[249,2327,2328],{"class":1751},"    name",[249,2330,1091],{"class":1002},[249,2332,2333],{"class":929}," sample-app-db-data\n",[10,2335,2336],{},"共有するつもりだったDBが空になったり、分離したつもりのDBを複数ブランチから共有したりしないよう、実際のVolume名を確認することが大切です。",[404,2338,2340],{"id":2339},"dbを共有したままmigrationを実行するのは危険","DBを共有したままmigrationを実行するのは危険",[10,2342,2343],{},"ブランチごとにmigrationの内容が違う場合、同じDBへ交互にmigrationを実行するとschemaとコードの対応が崩れる可能性があります。",[10,2345,2346],{},"たとえば、featureブランチでカラムを追加したあとに、mainブランチのコードから同じDBへ接続すると、想定していないschemaを参照することになります。カラムの削除や型変更を含むmigrationでは、データを失う危険もあります。",[10,2348,2349],{},"次のような場合は、DBやschemaもworktreeごとに分けたほうが安全です。",[470,2351,2352,2355,2358],{},[473,2353,2354],{},"破壊的なmigrationを試す",[473,2356,2357],{},"複数ブランチで異なるmigrationを並行して作る",[473,2359,2360],{},"テストデータをブランチごとに独立させたい",[10,2362,2363],{},"DBを共有する場合は、同時に実行するブランチ間でschemaに互換性があるかを確認し、必要なデータを事前にバックアップします。",[2117,2365,2368],{"title":2366,"type":2367},"コンテナーを分けてもDBが分かれるとは限らない","caution",[10,2369,2370],{},"接続先が同じ外部DBだったり、同じ名前付きVolumeを明示的に共有していたりすると、アプリコンテナーを分けてもデータは共有されます。コンテナー名だけでなく、接続先とVolumeの設定まで確認してください。",[28,2372,2373],{"id":2373},"どう使い分けるのが良さそうか",[10,2375,2376],{},"今回整理した構成は、次のように使い分けるのが良さそうです。",[38,2378,2379,2392],{},[41,2380,2381],{},[44,2382,2383,2386,2389],{},[47,2384,2385],{},"構成",[47,2387,2388],{},"向いている場面",[47,2390,2391],{},"注意点",[57,2393,2394,2405,2416],{},[44,2395,2396,2399,2402],{},[62,2397,2398],{},"worktreeごとにCompose一式を起動",[62,2400,2401],{},"アプリ、DB、Redisなどをブランチ単位で独立させたい",[62,2403,2404],{},"使用メモリやディスク容量が増える",[44,2406,2407,2410,2413],{},[62,2408,2409],{},"共通サービスだけDockerで起動",[62,2411,2412],{},"アプリをホスト上で手軽に複数起動したい",[62,2414,2415],{},"共有DBのmigrationに注意する",[44,2417,2418,2421,2424],{},[62,2419,2420],{},"1つのCompose環境だけ使う",[62,2422,2423],{},"実行して確認するブランチを同時に1つへ絞れる",[62,2425,2426],{},"別worktreeの変更は自動では反映されない",[10,2428,2429],{},"環境を完全に分離したい場合は、worktreeごとにproject名、ポート、Volumeを分ける方法が分かりやすいです。",[10,2431,2432],{},"一方、DBやRedisの状態を共有しても問題がなく、アプリケーションをホスト上で起動できるなら、共通サービスだけをDockerへ任せる構成が扱いやすいと感じました。",[28,2434,465],{"id":465},[10,2436,2437],{},"Git worktreeを使うと、1つのGitリポジトリに複数の作業ディレクトリを用意し、異なるブランチを並行して編集できます。",[10,2439,2440],{},"しかし、Dockerのbind mountが参照するのは、設定で指定されたホスト上のディレクトリだけです。別のworktreeを作成しても、既存コンテナーのmount先が自動的に切り替わることはありません。",[10,2442,2443],{},"今回ハマった原因は、Gitが管理するリポジトリの単位と、Dockerが参照するディレクトリの単位を混同していたことでした。",[1901,2445,2446],{},[10,2447,1905],{},[10,2449,2450],{},"この違いを理解すると、worktreeごとにCompose環境を分けるべきか、DBなどだけを共有するべきかを判断しやすくなります。",[10,2452,2453,2454,2457],{},"Git worktreeとDockerを組み合わせるときは、ブランチだけでなく、",[17,2455,2456],{},"どのホストディレクトリを、どのコンテナーへmountしているのか"," を確認することが大切だと学びました。",[499,2459,2460],{},"html pre.shiki code .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sHwdD, html code.shiki .sHwdD{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#546E7A;--shiki-default-font-style:italic;--shiki-dark:#676E95;--shiki-dark-font-style:italic}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .sbssI, html code.shiki .sbssI{--shiki-light:#F76D47;--shiki-default:#F78C6C;--shiki-dark:#F78C6C}html pre.shiki code .swJcz, html code.shiki .swJcz{--shiki-light:#E53935;--shiki-default:#F07178;--shiki-dark:#F07178}",{"title":170,"searchDepth":258,"depth":258,"links":2462},[2463,2464,2465,2466,2467,2468,2473,2474],{"id":1620,"depth":258,"text":1621},{"id":1657,"depth":258,"text":1658},{"id":1728,"depth":258,"text":1729},{"id":1911,"depth":258,"text":1912},{"id":2133,"depth":258,"text":2134},{"id":2227,"depth":258,"text":2228,"children":2469},[2470,2471,2472],{"id":2231,"depth":265,"text":2231},{"id":2246,"depth":265,"text":2247},{"id":2339,"depth":265,"text":2340},{"id":2373,"depth":258,"text":2373},{"id":465,"depth":258,"text":465},"Git worktreeで複数ブランチを並行開発したとき、変更が既存のDockerコンテナーへ反映されなかった原因を、bind mountの仕組みから整理します。",{},"2026-09-03",{"title":685,"description":2475},"articles\u002F2026\u002Fgit-worktree-with-docker-development",[2481,2482],"Git","Docker","\u002Fimages\u002Farticles\u002Fgit-worktree-with-docker-development.png","2zopLntSY8Ya7BGOnXbiIDpvrvdM5aVjWBBDkgAL7Ek",{"id":2486,"title":2487,"body":2488,"description":3154,"extension":517,"meta":3155,"navigation":261,"path":3156,"publishDate":3157,"published":261,"seo":3158,"stem":3159,"tags":3160,"thumbnail":3162,"updated":3163,"__hash__":3164},"articles\u002Farticles\u002F2026\u002Fsync-local-branch-after-stack-pr-rebase.md","GitHub上でStack PRをrebaseしたあとにローカルブランチを同期する方法",{"type":7,"value":2489,"toc":3134},[2490,2492,2499,2505,2508,2511,2525,2528,2531,2534,2537,2543,2546,2552,2569,2585,2591,2594,2597,2600,2606,2609,2613,2625,2628,2634,2637,2665,2669,2684,2693,2697,2715,2718,2729,2735,2738,2741,2770,2773,2777,2784,2787,2805,2811,2814,2817,2827,2831,2834,2848,2851,2857,2860,2863,2866,2916,2923,2926,2929,2993,2996,3000,3003,3010,3082,3085,3087,3090,3093,3118,3124,3131],[10,2491,12],{},[10,2493,2494,2495,2498],{},"先日、GitHub上でStack PRをrebaseしたあと、ローカルブランチからpushしようとしたところ、",[172,2496,2497],{},"non-fast-forward"," エラーが発生しました。",[164,2500,2503],{"className":2501,"code":2502,"language":169,"meta":170},[167],"! [rejected] branch-name -> branch-name (non-fast-forward)\nerror: failed to push some refs\n",[172,2504,2502],{"__ignoreMap":170},[10,2506,2507],{},"rebaseによってコミット履歴がどう変わるかは理解していたものの、その結果をローカル環境へどう反映すればよいのか分かっていませんでした。",[10,2509,2510],{},"今回は、GitHub上でrebase済みのブランチを正として、ローカルブランチを安全に同期する方法を整理します。",[2117,2512,2514],{"title":2513,"type":2367},"resetする前にローカルの変更を確認する",[10,2515,2516,2517,2520,2521,2524],{},"この記事では ",[172,2518,2519],{},"git reset --hard"," を使用します。",[2522,2523],"br",{},"未コミットの変更やローカルにしかないコミットが不要であることを確認してから実行してください。",[28,2526,2527],{"id":2527},"rebase後にpushできなくなる理由",[10,2529,2530],{},"rebaseは、既存コミットの親を付け替えて履歴を並べ直す処理です。",[10,2532,2533],{},"コミットの変更内容が同じでも、親コミットが変わるとコミットIDも変わります。",[404,2535,2536],{"id":2536},"rebase前",[164,2538,2541],{"className":2539,"code":2540,"language":169,"meta":170},[167],"A---B---C       親ブランチ\n     \\\n      D---E     子ブランチ\n",[172,2542,2540],{"__ignoreMap":170},[404,2544,2545],{"id":2545},"rebase後",[164,2547,2550],{"className":2548,"code":2549,"language":169,"meta":170},[167],"A---B---C---D'---E'\n",[172,2551,2549],{"__ignoreMap":170},[10,2553,2554,2557,2558,2561,2562,2557,2565,2568],{},[172,2555,2556],{},"D"," と ",[172,2559,2560],{},"D'","、",[172,2563,2564],{},"E",[172,2566,2567],{},"E'"," は変更内容がほぼ同じでも、Git上では異なるコミットです。",[10,2570,2571,2572,2557,2574,2576,2577,2579,2580,2557,2582,2584],{},"GitHub上でrebaseした場合、リモートブランチは新しい ",[172,2573,2560],{},[172,2575,2567],{}," を参照します。",[2522,2578],{},"一方、ローカルブランチは古い ",[172,2581,2556],{},[172,2583,2564],{}," を参照したままです。",[164,2586,2589],{"className":2587,"code":2588,"language":169,"meta":170},[167],"              D---E       ローカル\n             \u002F\nA---B---C\n             \\\n              D'---E'     リモート\n",[172,2590,2588],{"__ignoreMap":170},[10,2592,2593],{},"ローカルの履歴がリモートの直接の続きではないため、通常のpushは拒否されます。コードの内容ではなく、コミット履歴が分岐していることが原因です。",[28,2595,2596],{"id":2596},"ローカルブランチを同期する",[10,2598,2599],{},"ここでは、次のブランチにいる状態で同期するものとします。",[164,2601,2604],{"className":2602,"code":2603,"language":169,"meta":170},[167],"feature\u002Fsample-docs\n",[172,2605,2603],{"__ignoreMap":170},[10,2607,2608],{},"実行時は、自分が同期したいブランチ名へ置き換えてください。",[404,2610,2612],{"id":2611},"_1-未コミットの変更を確認する","1. 未コミットの変更を確認する",[164,2614,2616],{"className":1671,"code":2615,"language":1673,"meta":170,"style":170},"git status\n",[172,2617,2618],{"__ignoreMap":170},[249,2619,2620,2622],{"class":251,"line":252},[249,2621,1688],{"class":925},[249,2623,2624],{"class":929}," status\n",[10,2626,2627],{},"次のように表示されれば、作業ツリーはクリーンです。",[164,2629,2632],{"className":2630,"code":2631,"language":169,"meta":170},[167],"nothing to commit, working tree clean\n",[172,2633,2631],{"__ignoreMap":170},[10,2635,2636],{},"変更を残したい場合は、先にコミットするか、未追跡ファイルも含めてstashします。",[164,2638,2640],{"className":1671,"code":2639,"language":1673,"meta":170,"style":170},"git stash push -u -m \"rebase後の同期前に一時退避\"\n",[172,2641,2642],{"__ignoreMap":170},[249,2643,2644,2646,2649,2652,2655,2658,2660,2663],{"class":251,"line":252},[249,2645,1688],{"class":925},[249,2647,2648],{"class":929}," stash",[249,2650,2651],{"class":929}," push",[249,2653,2654],{"class":929}," -u",[249,2656,2657],{"class":929}," -m",[249,2659,1109],{"class":1002},[249,2661,2662],{"class":929},"rebase後の同期前に一時退避",[249,2664,1114],{"class":1002},[404,2666,2668],{"id":2667},"_2-リモートの最新情報を取得する","2. リモートの最新情報を取得する",[164,2670,2672],{"className":1671,"code":2671,"language":1673,"meta":170,"style":170},"git fetch origin\n",[172,2673,2674],{"__ignoreMap":170},[249,2675,2676,2678,2681],{"class":251,"line":252},[249,2677,1688],{"class":925},[249,2679,2680],{"class":929}," fetch",[249,2682,2683],{"class":929}," origin\n",[10,2685,2686,2689,2690,2692],{},[172,2687,2688],{},"fetch"," は、リモートの最新コミットとブランチ情報を取得します。",[2522,2691],{},"この操作だけでは、現在のローカルブランチや作業中のファイルは変更されません。",[404,2694,2696],{"id":2695},"_3-ローカルをリモートと同じ状態にする","3. ローカルをリモートと同じ状態にする",[164,2698,2700],{"className":1671,"code":2699,"language":1673,"meta":170,"style":170},"git reset --hard origin\u002Ffeature\u002Fsample-docs\n",[172,2701,2702],{"__ignoreMap":170},[249,2703,2704,2706,2709,2712],{"class":251,"line":252},[249,2705,1688],{"class":925},[249,2707,2708],{"class":929}," reset",[249,2710,2711],{"class":929}," --hard",[249,2713,2714],{"class":929}," origin\u002Ffeature\u002Fsample-docs\n",[10,2716,2717],{},"このコマンドによって、次の状態がリモートブランチにそろいます。",[470,2719,2720,2723,2726],{},[473,2721,2722],{},"現在のローカルブランチが参照するコミット",[473,2724,2725],{},"ステージング領域",[473,2727,2728],{},"Gitが追跡している作業ツリー上のファイル",[10,2730,2731,2732,2734],{},"なお、",[172,2733,2519],{}," だけでは未追跡ファイルは削除されません。",[28,2736,2737],{"id":2737},"実行コマンドのまとめ",[10,2739,2740],{},"未コミットの変更や残したいローカルコミットがない場合は、次の流れで同期できます。",[164,2742,2744],{"className":1671,"code":2743,"language":1673,"meta":170,"style":170},"git status\ngit fetch origin\ngit reset --hard origin\u002Ffeature\u002Fsample-docs\n",[172,2745,2746,2752,2760],{"__ignoreMap":170},[249,2747,2748,2750],{"class":251,"line":252},[249,2749,1688],{"class":925},[249,2751,2624],{"class":929},[249,2753,2754,2756,2758],{"class":251,"line":258},[249,2755,1688],{"class":925},[249,2757,2680],{"class":929},[249,2759,2683],{"class":929},[249,2761,2762,2764,2766,2768],{"class":251,"line":265},[249,2763,1688],{"class":925},[249,2765,2708],{"class":929},[249,2767,2711],{"class":929},[249,2769,2714],{"class":929},[10,2771,2772],{},"ブランチ名は、実際に同期するブランチへ置き換えてください。",[28,2774,2776],{"id":2775},"git-pullを使わない理由","git pullを使わない理由",[10,2778,2779,2780,2783],{},"GitHub上のブランチはrebase後の履歴、ローカルブランチはrebase前の履歴を参照している状態で ",[172,2781,2782],{},"git pull"," を実行すると、Gitはそれぞれの履歴を統合しようとします。",[10,2785,2786],{},"実際にpullしたところ、ローカルとリモートの履歴が分岐しているため、統合方法を指定するよう求められました。",[164,2788,2790],{"className":1671,"code":2789,"language":1673,"meta":170,"style":170},"git pull origin feature\u002Fsample-docs\n",[172,2791,2792],{"__ignoreMap":170},[249,2793,2794,2796,2799,2802],{"class":251,"line":252},[249,2795,1688],{"class":925},[249,2797,2798],{"class":929}," pull",[249,2800,2801],{"class":929}," origin",[249,2803,2804],{"class":929}," feature\u002Fsample-docs\n",[164,2806,2809],{"className":2807,"code":2808,"language":169,"meta":170},[167],"hint: You have divergent branches and need to specify how to reconcile them.\nhint: You can do so by running one of the following commands sometime before\nhint: your next pull:\nhint:\nhint:   git config pull.rebase false  # merge\nhint:   git config pull.rebase true   # rebase\nhint:   git config pull.ff only       # fast-forward only\nfatal: Need to specify how to reconcile divergent branches.\n",[172,2810,2808],{"__ignoreMap":170},[10,2812,2813],{},"Gitは、分岐した履歴をmergeするのか、rebaseするのか、fast-forwardだけを許可するのかを自動では判断できません。",[10,2815,2816],{},"GitHub上で完了したrebase結果を正とするのであれば、古いローカル履歴を統合する必要はありません。",[10,2818,2819,2820,2822,2823,2826],{},"そのため、",[172,2821,2688],{}," でリモートの状態を取得し、内容を確認してから ",[172,2824,2825],{},"reset --hard"," でローカルを合わせる方法が明確です。",[28,2828,2830],{"id":2829},"force-pushを使わない理由","force pushを使わない理由",[10,2832,2833],{},"GitHub上でrebaseした直後に古いローカルブランチからforce pushすると、GitHubが作った新しい履歴を古い履歴で上書きする可能性があります。",[164,2835,2837],{"className":1671,"code":2836,"language":1673,"meta":170,"style":170},"git push --force\n",[172,2838,2839],{"__ignoreMap":170},[249,2840,2841,2843,2845],{"class":251,"line":252},[249,2842,1688],{"class":925},[249,2844,2651],{"class":929},[249,2846,2847],{"class":929}," --force\n",[10,2849,2850],{},"この場面で必要なのは、リモートをローカルへ合わせることではなく、ローカルをrebase済みのリモートへ合わせることです。",[164,2852,2855],{"className":2853,"code":2854,"language":169,"meta":170},[167],"避けたい操作:\n古いローカル履歴 → リモートへforce push\n\n行いたい操作:\nrebase済みリモート履歴 → ローカルへ反映\n",[172,2856,2854],{"__ignoreMap":170},[28,2858,2859],{"id":2859},"ローカルの変更を残したい場合",[404,2861,2862],{"id":2862},"未コミットの変更がある場合",[10,2864,2865],{},"未コミットの変更は、同期前にstashできます。",[164,2867,2869],{"className":1671,"code":2868,"language":1673,"meta":170,"style":170},"git stash push -u -m \"rebase後の同期前に一時退避\"\ngit fetch origin\ngit reset --hard origin\u002Ffeature\u002Fsample-docs\ngit stash pop\n",[172,2870,2871,2889,2897,2907],{"__ignoreMap":170},[249,2872,2873,2875,2877,2879,2881,2883,2885,2887],{"class":251,"line":252},[249,2874,1688],{"class":925},[249,2876,2648],{"class":929},[249,2878,2651],{"class":929},[249,2880,2654],{"class":929},[249,2882,2657],{"class":929},[249,2884,1109],{"class":1002},[249,2886,2662],{"class":929},[249,2888,1114],{"class":1002},[249,2890,2891,2893,2895],{"class":251,"line":258},[249,2892,1688],{"class":925},[249,2894,2680],{"class":929},[249,2896,2683],{"class":929},[249,2898,2899,2901,2903,2905],{"class":251,"line":265},[249,2900,1688],{"class":925},[249,2902,2708],{"class":929},[249,2904,2711],{"class":929},[249,2906,2714],{"class":929},[249,2908,2909,2911,2913],{"class":251,"line":271},[249,2910,1688],{"class":925},[249,2912,2648],{"class":929},[249,2914,2915],{"class":929}," pop\n",[10,2917,2918,2919,2922],{},"ただし、rebase後のコードと変更箇所が重なっていると、",[172,2920,2921],{},"stash pop"," 時にコンフリクトする可能性があります。",[404,2924,2925],{"id":2925},"未pushのコミットがある場合",[10,2927,2928],{},"ローカルに必要なコミットがある場合は、コミットIDを控えるか、退避用ブランチを作ってから同期します。その後、必要なコミットをcherry-pickします。",[164,2930,2932],{"className":1671,"code":2931,"language":1673,"meta":170,"style":170},"git fetch origin\ngit log --oneline origin\u002Ffeature\u002Fsample-docs..HEAD\ngit branch backup\u002Fsample-docs-before-sync\ngit reset --hard origin\u002Ffeature\u002Fsample-docs\ngit cherry-pick \u003C残したいコミットID>\n",[172,2933,2934,2942,2955,2965,2975],{"__ignoreMap":170},[249,2935,2936,2938,2940],{"class":251,"line":252},[249,2937,1688],{"class":925},[249,2939,2680],{"class":929},[249,2941,2683],{"class":929},[249,2943,2944,2946,2949,2952],{"class":251,"line":258},[249,2945,1688],{"class":925},[249,2947,2948],{"class":929}," log",[249,2950,2951],{"class":929}," --oneline",[249,2953,2954],{"class":929}," origin\u002Ffeature\u002Fsample-docs..HEAD\n",[249,2956,2957,2959,2962],{"class":251,"line":265},[249,2958,1688],{"class":925},[249,2960,2961],{"class":929}," branch",[249,2963,2964],{"class":929}," backup\u002Fsample-docs-before-sync\n",[249,2966,2967,2969,2971,2973],{"class":251,"line":271},[249,2968,1688],{"class":925},[249,2970,2708],{"class":929},[249,2972,2711],{"class":929},[249,2974,2714],{"class":929},[249,2976,2977,2979,2982,2985,2988,2990],{"class":251,"line":277},[249,2978,1688],{"class":925},[249,2980,2981],{"class":929}," cherry-pick",[249,2983,2984],{"class":1002}," \u003C",[249,2986,2987],{"class":929},"残したいコミットI",[249,2989,2556],{"class":1173},[249,2991,2992],{"class":1002},">\n",[10,2994,2995],{},"cherry-pickでも、rebase後の変更と重なっている場合はコンフリクトの解消が必要です。",[28,2997,2999],{"id":2998},"複数のstackブランチを同期する場合","複数のStackブランチを同期する場合",[10,3001,3002],{},"GitHubのStack rebaseでは、Stack内の複数ブランチが更新されます。",[10,3004,3005,3006,3009],{},"ローカルでも複数の子ブランチを使い続ける場合は、",[172,3007,3008],{},"git fetch origin"," を実行したあと、それぞれを対応するリモートブランチへ同期します。",[164,3011,3013],{"className":1671,"code":3012,"language":1673,"meta":170,"style":170},"git switch feature\u002Fsample-api\ngit reset --hard origin\u002Ffeature\u002Fsample-api\n\ngit switch feature\u002Fsample-ui\ngit reset --hard origin\u002Ffeature\u002Fsample-ui\n\ngit switch feature\u002Fsample-docs\ngit reset --hard origin\u002Ffeature\u002Fsample-docs\n",[172,3014,3015,3025,3036,3040,3049,3060,3064,3072],{"__ignoreMap":170},[249,3016,3017,3019,3022],{"class":251,"line":252},[249,3018,1688],{"class":925},[249,3020,3021],{"class":929}," switch",[249,3023,3024],{"class":929}," feature\u002Fsample-api\n",[249,3026,3027,3029,3031,3033],{"class":251,"line":258},[249,3028,1688],{"class":925},[249,3030,2708],{"class":929},[249,3032,2711],{"class":929},[249,3034,3035],{"class":929}," origin\u002Ffeature\u002Fsample-api\n",[249,3037,3038],{"class":251,"line":265},[249,3039,262],{"emptyLinePlaceholder":261},[249,3041,3042,3044,3046],{"class":251,"line":271},[249,3043,1688],{"class":925},[249,3045,3021],{"class":929},[249,3047,3048],{"class":929}," feature\u002Fsample-ui\n",[249,3050,3051,3053,3055,3057],{"class":251,"line":277},[249,3052,1688],{"class":925},[249,3054,2708],{"class":929},[249,3056,2711],{"class":929},[249,3058,3059],{"class":929}," origin\u002Ffeature\u002Fsample-ui\n",[249,3061,3062],{"class":251,"line":283},[249,3063,262],{"emptyLinePlaceholder":261},[249,3065,3066,3068,3070],{"class":251,"line":288},[249,3067,1688],{"class":925},[249,3069,3021],{"class":929},[249,3071,2804],{"class":929},[249,3073,3074,3076,3078,3080],{"class":251,"line":294},[249,3075,1688],{"class":925},[249,3077,2708],{"class":929},[249,3079,2711],{"class":929},[249,3081,2714],{"class":929},[10,3083,3084],{},"作業を続ける最上位ブランチしか使わない場合は、ひとまずそのブランチだけ同期すれば作業を再開できます。あとから途中のブランチへ戻る場合は、その時点で同期が必要です。",[28,3086,465],{"id":465},[10,3088,3089],{},"GitHub上でStack PRをrebaseすると、リモート側のコミットIDが作り直されます。そのため、古い履歴を参照しているローカルブランチから通常のpushはできなくなります。",[10,3091,3092],{},"同期するときの基本方針は次のとおりです。",[638,3094,3095,3101,3104,3109,3115],{},[473,3096,3097,3100],{},[172,3098,3099],{},"git status"," で未コミットの変更を確認する",[473,3102,3103],{},"必要であればstashや退避用ブランチを作る",[473,3105,3106,3108],{},[172,3107,3008],{}," でrebase後の履歴を取得する",[473,3110,3111,3114],{},[172,3112,3113],{},"git reset --hard origin\u002F\u003Cブランチ名>"," で同期する",[473,3116,3117],{},"古いローカル履歴からforce pushしない",[10,3119,3120,3121,3123],{},"rebase後にpushできなくなるのは異常ではありません。",[2522,3122],{},"GitHubとローカルが異なるコミット履歴を参照しているために起きる、Gitとして正常な挙動です。",[10,3125,3126,3127,3130],{},"今回の経験を通して、rebaseによる履歴の変化だけでなく、",[17,3128,3129],{},"どちらの履歴を正として、どちらを合わせるのか"," を判断することが大切だと学びました。",[499,3132,3133],{},"html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}",{"title":170,"searchDepth":258,"depth":258,"links":3135},[3136,3140,3145,3146,3147,3148,3152,3153],{"id":2527,"depth":258,"text":2527,"children":3137},[3138,3139],{"id":2536,"depth":265,"text":2536},{"id":2545,"depth":265,"text":2545},{"id":2596,"depth":258,"text":2596,"children":3141},[3142,3143,3144],{"id":2611,"depth":265,"text":2612},{"id":2667,"depth":265,"text":2668},{"id":2695,"depth":265,"text":2696},{"id":2737,"depth":258,"text":2737},{"id":2775,"depth":258,"text":2776},{"id":2829,"depth":258,"text":2830},{"id":2859,"depth":258,"text":2859,"children":3149},[3150,3151],{"id":2862,"depth":265,"text":2862},{"id":2925,"depth":265,"text":2925},{"id":2998,"depth":258,"text":2999},{"id":465,"depth":258,"text":465},"GitHub上でStack PRをrebaseしたあと、古いコミット履歴が残るローカルブランチをrebase済みのリモートブランチへ安全に同期する手順を紹介します。",{},"\u002Farticles\u002F2026\u002Fsync-local-branch-after-stack-pr-rebase","2026-08-27",{"title":2487,"description":3154},"articles\u002F2026\u002Fsync-local-branch-after-stack-pr-rebase",[2481,3161],"GitHub","\u002Fimages\u002Farticles\u002Fsync-local-branch-after-stack-pr-rebase.png","2026-08-29","dBjHJRNGHtkl1XTP0Qbhr3-DHoHrffQddWseIgn7_s0",{"id":3166,"title":3167,"body":3168,"description":3769,"extension":517,"meta":3770,"navigation":261,"path":3771,"publishDate":3772,"published":261,"seo":3773,"stem":3774,"tags":3775,"thumbnail":3777,"updated":3772,"__hash__":3778},"articles\u002Farticles\u002F2026\u002Fresolve-mac-system-data-storage-shortage-with-docker.md","Macの「システムデータ」が267GBに増えた原因はDockerだった",{"type":7,"value":3169,"toc":3759},[3170,3172,3179,3182,3189,3192,3198,3202,3205,3211,3214,3220,3223,3226,3229,3265,3274,3281,3287,3293,3321,3328,3334,3340,3368,3371,3377,3380,3383,3387,3390,3405,3408,3414,3417,3455,3461,3465,3468,3486,3492,3495,3501,3504,3508,3511,3523,3526,3541,3544,3550,3557,3561,3564,3581,3584,3590,3593,3596,3605,3614,3617,3623,3626,3640,3643,3646,3649,3692,3695,3702,3704,3707,3735,3738,3741,3753,3756],[10,3171,12],{},[10,3173,3174,3175,3178],{},"Xcodeをインストールしてアプリ開発するため、一応MacBookのストレージを確認したところ、「システムデータ」が ",[17,3176,3177],{},"267GB"," まで増えていました、、",[10,3180,3181],{},"システムデータはmacOSがまとめて表示している領域で、ストレージ設定を見ただけでは、何に容量を使っているのか全然分かりませんでした。",[10,3183,3184,3185,3188],{},"そこでターミナルから使用量を調べた結果、主な原因は ",[17,3186,3187],{},"Docker Desktopのデータ"," でした。",[10,3190,3191],{},"今回は、原因を特定した手順と、DockerのBuild Cache、Image、Volumeを整理して空き容量を増やした方法を紹介します。",[2117,3193,3195],{"title":3194,"type":2367},"削除前に必要なデータを確認する",[10,3196,3197],{},"この記事にはDockerのデータを削除するコマンドが登場します。必要なImageやVolumeまで削除しないよう、各コマンドの対象を確認し、DBなどの重要なデータは事前にバックアップしてください。",[28,3199,3201],{"id":3200},"macのストレージ状況を確認する","Macのストレージ状況を確認する",[10,3203,3204],{},"macOSでは、次の順番でストレージの使用状況を確認できます。",[164,3206,3209],{"className":3207,"code":3208,"language":169,"meta":170},[167],"メニュー\n  ↓\nシステム設定\n  ↓\n一般\n  ↓\nストレージ\n",[172,3210,3208],{"__ignoreMap":170},[10,3212,3213],{},"今回確認したときは、システムデータだけで267GBを使用していました。",[164,3215,3218],{"className":3216,"code":3217,"language":169,"meta":170},[167],"システムデータ  267GB\n",[172,3219,3217],{"__ignoreMap":170},[10,3221,3222],{},"通常のファイル整理だけでは解消できそうになかったため、どのディレクトリが容量を使っているのか調べました。",[28,3224,3225],{"id":3225},"容量を使っているディレクトリを調べる",[10,3227,3228],{},"まず、ホームディレクトリ直下の使用量を確認します。",[164,3230,3232],{"className":1671,"code":3231,"language":1673,"meta":170,"style":170},"du -h -d 1 ~ 2>\u002Fdev\u002Fnull | sort -h\n",[172,3233,3234],{"__ignoreMap":170},[249,3235,3236,3239,3242,3244,3247,3250,3253,3256,3259,3262],{"class":251,"line":252},[249,3237,3238],{"class":925},"du",[249,3240,3241],{"class":929}," -h",[249,3243,2162],{"class":929},[249,3245,3246],{"class":1772}," 1",[249,3248,3249],{"class":929}," ~",[249,3251,3252],{"class":1002}," 2>",[249,3254,3255],{"class":929},"\u002Fdev\u002Fnull",[249,3257,3258],{"class":1002}," |",[249,3260,3261],{"class":925}," sort",[249,3263,3264],{"class":929}," -h\n",[10,3266,3267,3269,3270,3273],{},[172,3268,3238],{}," はディレクトリごとの使用量を表示するコマンドです。",[172,3271,3272],{},"-d 1"," を指定すると、1階層下までを集計できます。",[10,3275,3276,3277,3280],{},"結果を見ると、",[172,3278,3279],{},"~\u002FLibrary"," が約254GBを占めていました。",[164,3282,3285],{"className":3283,"code":3284,"language":169,"meta":170},[167],"254G  \u002FUsers\u002Fxxxxx\u002FLibrary\n",[172,3286,3284],{"__ignoreMap":170},[10,3288,3289,3290,3292],{},"次に、",[172,3291,3279],{}," の内訳を確認します。",[164,3294,3296],{"className":1671,"code":3295,"language":1673,"meta":170,"style":170},"du -h -d 1 ~\u002FLibrary 2>\u002Fdev\u002Fnull | sort -h\n",[172,3297,3298],{"__ignoreMap":170},[249,3299,3300,3302,3304,3306,3308,3311,3313,3315,3317,3319],{"class":251,"line":252},[249,3301,3238],{"class":925},[249,3303,3241],{"class":929},[249,3305,2162],{"class":929},[249,3307,3246],{"class":1772},[249,3309,3310],{"class":929}," ~\u002FLibrary",[249,3312,3252],{"class":1002},[249,3314,3255],{"class":929},[249,3316,3258],{"class":1002},[249,3318,3261],{"class":925},[249,3320,3264],{"class":929},[10,3322,3323,3324,3327],{},"ここでは、",[172,3325,3326],{},"Containers"," が約210GBを使用していました。",[164,3329,3332],{"className":3330,"code":3331,"language":169,"meta":170},[167],"210G  \u002FUsers\u002Fxxxxx\u002FLibrary\u002FContainers\n",[172,3333,3331],{"__ignoreMap":170},[10,3335,3336,3337,3339],{},"さらに、",[172,3338,3326],{}," の中を調べます。",[164,3341,3343],{"className":1671,"code":3342,"language":1673,"meta":170,"style":170},"du -h -d 1 ~\u002FLibrary\u002FContainers 2>\u002Fdev\u002Fnull | sort -h\n",[172,3344,3345],{"__ignoreMap":170},[249,3346,3347,3349,3351,3353,3355,3358,3360,3362,3364,3366],{"class":251,"line":252},[249,3348,3238],{"class":925},[249,3350,3241],{"class":929},[249,3352,2162],{"class":929},[249,3354,3246],{"class":1772},[249,3356,3357],{"class":929}," ~\u002FLibrary\u002FContainers",[249,3359,3252],{"class":1002},[249,3361,3255],{"class":929},[249,3363,3258],{"class":1002},[249,3365,3261],{"class":925},[249,3367,3264],{"class":929},[10,3369,3370],{},"すると、Docker Desktopのコンテナーディレクトリが約210GBを占めていることが分かりました。",[164,3372,3375],{"className":3373,"code":3374,"language":169,"meta":170},[167],"210G  \u002FUsers\u002Fxxxxx\u002FLibrary\u002FContainers\u002Fcom.docker.docker\n",[172,3376,3374],{"__ignoreMap":170},[10,3378,3379],{},"macOS版のDocker Desktopは、Linuxコンテナーを動かすための仮想ディスクをMac上に保存しています。",[10,3381,3382],{},"そのためDockerのImage、Volume、Build Cacheなどが増えると、macOSではシステムデータとして大きく表示されることがあります。",[28,3384,3386],{"id":3385},"dockerの使用量を確認する","Dockerの使用量を確認する",[10,3388,3389],{},"Docker側の内訳は、次のコマンドで確認できます。",[164,3391,3393],{"className":1671,"code":3392,"language":1673,"meta":170,"style":170},"docker system df\n",[172,3394,3395],{"__ignoreMap":170},[249,3396,3397,3399,3402],{"class":251,"line":252},[249,3398,1828],{"class":925},[249,3400,3401],{"class":929}," system",[249,3403,3404],{"class":929}," df\n",[10,3406,3407],{},"今回の主な結果は次のとおりでした。",[164,3409,3412],{"className":3410,"code":3411,"language":169,"meta":170},[167],"TYPE            TOTAL     SIZE\nImages          20        107.6GB\nContainers      12        526MB\nLocal Volumes   46        100.2GB\nBuild Cache     196       73GB\n",[172,3413,3411],{"__ignoreMap":170},[10,3415,3416],{},"特に容量が大きかったのは、次の3項目です。",[38,3418,3419,3429],{},[41,3420,3421],{},[44,3422,3423,3425],{},[47,3424,834],{},[47,3426,3428],{"align":3427},"right","容量",[57,3430,3431,3439,3447],{},[44,3432,3433,3436],{},[62,3434,3435],{},"Images",[62,3437,3438],{"align":3427},"107.6GB",[44,3440,3441,3444],{},[62,3442,3443],{},"Local Volumes",[62,3445,3446],{"align":3427},"100.2GB",[44,3448,3449,3452],{},[62,3450,3451],{},"Build Cache",[62,3453,3454],{"align":3427},"73GB",[10,3456,3457,3460],{},[172,3458,3459],{},"docker system df"," の数値には共有レイヤーなども含まれるため、表示された値の合計が、そのままMac上で解放できる容量になるとは限りません。ただし、どの種類のデータから調べるべきかを判断する目安になります。",[28,3462,3464],{"id":3463},"build-cacheを削除する","Build Cacheを削除する",[10,3466,3467],{},"まず、最も整理しやすいBuild Cacheを削除しました。",[164,3469,3471],{"className":1671,"code":3470,"language":1673,"meta":170,"style":170},"docker builder prune -a\n",[172,3472,3473],{"__ignoreMap":170},[249,3474,3475,3477,3480,3483],{"class":251,"line":252},[249,3476,1828],{"class":925},[249,3478,3479],{"class":929}," builder",[249,3481,3482],{"class":929}," prune",[249,3484,3485],{"class":929}," -a\n",[10,3487,3488,3491],{},[172,3489,3490],{},"-a"," を付けると、現在使われていないBuild Cacheがまとめて削除されます。実行前には削除対象と確認メッセージが表示されます。",[10,3493,3494],{},"今回、Build Cacheは73GBから0Bになりました。",[164,3496,3499],{"className":3497,"code":3498,"language":169,"meta":170},[167],"73GB → 0B\n",[172,3500,3498],{"__ignoreMap":170},[10,3502,3503],{},"Build CacheはDocker Imageをビルドするときに再利用される中間データです。削除しても必要に応じて再生成されますが、次回のビルドには時間がかかる場合があります。",[28,3505,3507],{"id":3506},"不要なimageを整理する","不要なImageを整理する",[10,3509,3510],{},"次に、保存されているImageを確認しました。",[164,3512,3514],{"className":1671,"code":3513,"language":1673,"meta":170,"style":170},"docker images\n",[172,3515,3516],{"__ignoreMap":170},[249,3517,3518,3520],{"class":251,"line":252},[249,3519,1828],{"class":925},[249,3521,3522],{"class":929}," images\n",[10,3524,3525],{},"まずは、タグがなく、コンテナーから参照されていないdangling imageを削除します。",[164,3527,3529],{"className":1671,"code":3528,"language":1673,"meta":170,"style":170},"docker image prune\n",[172,3530,3531],{"__ignoreMap":170},[249,3532,3533,3535,3538],{"class":251,"line":252},[249,3534,1828],{"class":925},[249,3536,3537],{"class":929}," image",[249,3539,3540],{"class":929}," prune\n",[10,3542,3543],{},"今回の削除量は約2.4GBでした。",[164,3545,3548],{"className":3546,"code":3547,"language":169,"meta":170},[167],"Total reclaimed space: 2.355GB\n",[172,3549,3547],{"__ignoreMap":170},[10,3551,3552,3553,3556],{},"すべての未使用Imageを対象にする ",[172,3554,3555],{},"docker image prune -a"," もありますが、次回の起動時に再取得が必要になるImageまで削除されます。今回は一覧を確認しながら、必要なImageを残して整理しました。",[28,3558,3560],{"id":3559},"大きなvolumeの中身を調べる","大きなVolumeの中身を調べる",[10,3562,3563],{},"Volumeごとの詳しい使用量は、次のコマンドで確認できます。",[164,3565,3567],{"className":1671,"code":3566,"language":1673,"meta":170,"style":170},"docker system df -v\n",[172,3568,3569],{"__ignoreMap":170},[249,3570,3571,3573,3575,3578],{"class":251,"line":252},[249,3572,1828],{"class":925},[249,3574,3401],{"class":929},[249,3576,3577],{"class":929}," df",[249,3579,3580],{"class":929}," -v\n",[10,3582,3583],{},"確認したところ、開発用DBのデータを保存しているVolumeが84.28GBを使用していました。",[164,3585,3588],{"className":3586,"code":3587,"language":169,"meta":170},[167],"xxxxxx_db-store  84.28GB\n",[172,3589,3587],{"__ignoreMap":170},[10,3591,3592],{},"このVolumeは現在利用しているプロジェクトのDBだったため、Volume自体は削除できません。そこで、DBの中に残っている不要な開発用スキーマを確認し、必要なデータではないことを確かめてから削除しました。",[10,3594,3595],{},"MySQLでは、次のSQLでスキーマを削除できます。",[164,3597,3599],{"className":243,"code":3598,"language":245,"meta":170,"style":170},"DROP SCHEMA schema_name;\n",[172,3600,3601],{"__ignoreMap":170},[249,3602,3603],{"class":251,"line":252},[249,3604,3598],{},[2117,3606,3608],{"title":3607,"type":2367},"DROP SCHEMAは元に戻せない",[10,3609,3610,3613],{},[172,3611,3612],{},"DROP SCHEMA"," を実行すると、スキーマ内のテーブルやデータも削除されます。対象名をよく確認し、必要に応じてバックアップを取得してから実行してください。",[10,3615,3616],{},"不要なスキーマを整理した結果、Local Volumesの使用量は100.2GBから53.89GBまで減りました。",[164,3618,3621],{"className":3619,"code":3620,"language":169,"meta":170},[167],"100.2GB → 53.89GB\n",[172,3622,3620],{"__ignoreMap":170},[10,3624,3625],{},"なお、使われていないVolumeをまとめて削除する場合は、次のコマンドを利用できます。",[164,3627,3629],{"className":1671,"code":3628,"language":1673,"meta":170,"style":170},"docker volume prune\n",[172,3630,3631],{"__ignoreMap":170},[249,3632,3633,3635,3638],{"class":251,"line":252},[249,3634,1828],{"class":925},[249,3636,3637],{"class":929}," volume",[249,3639,3540],{"class":929},[10,3641,3642],{},"VolumeにはDBなどの永続データが保存されていることがあります。名前や利用状況を確認せずに実行するのは避けたほうが安全です。",[28,3644,3645],{"id":3645},"整理後の結果",[10,3647,3648],{},"整理前と整理後のDocker使用量は、次のようになりました。",[38,3650,3651,3663],{},[41,3652,3653],{},[44,3654,3655,3657,3660],{},[47,3656,834],{},[47,3658,3659],{"align":3427},"整理前",[47,3661,3662],{"align":3427},"整理後",[57,3664,3665,3674,3683],{},[44,3666,3667,3669,3671],{},[62,3668,3435],{},[62,3670,3438],{"align":3427},[62,3672,3673],{"align":3427},"50.4GB",[44,3675,3676,3678,3680],{},[62,3677,3443],{},[62,3679,3446],{"align":3427},[62,3681,3682],{"align":3427},"53.89GB",[44,3684,3685,3687,3689],{},[62,3686,3451],{},[62,3688,3454],{"align":3427},[62,3690,3691],{"align":3427},"0B",[10,3693,3694],{},"Build Cacheの削除と、不要なImage、DBスキーマの整理によって、Docker関連のデータを100GB以上削減できました。",[10,3696,3697,3698,3701],{},"Docker Desktopの仮想ディスクはスパースファイルとして管理されるため、Docker上でデータを削除しても、ファイル自体の見かけの最大サイズがすぐに小さくならない場合があります。実際の空き容量はmacOSのストレージ画面や ",[172,3699,3700],{},"df -h"," でも確認すると確実です。",[28,3703,465],{"id":465},[10,3705,3706],{},"Macのシステムデータが異常に増えた場合は、次の順番で調べると原因を絞り込めます。",[638,3708,3709,3717,3723,3729,3732],{},[473,3710,3711,3713,3714,3716],{},[172,3712,3238],{}," で ",[172,3715,3279],{}," の使用量を確認する",[473,3718,3719,3722],{},[172,3720,3721],{},"~\u002FLibrary\u002FContainers"," に大きなディレクトリがないか確認する",[473,3724,3725,3726,3728],{},"Docker Desktopが大きい場合は ",[172,3727,3459],{}," で内訳を確認する",[473,3730,3731],{},"不要なBuild CacheやImageを整理する",[473,3733,3734],{},"大きなVolumeは削除せず、保存されているデータの中身まで確認する",[10,3736,3737],{},"特にDocker Desktopを長期間使っていると、過去のBuild CacheやImage、開発用DBのデータが蓄積します。",[10,3739,3740],{},"Macの容量不足に気づいてから慌てないよう、定期的に次のコマンドで使用量を確認しておくと安心です。",[164,3742,3743],{"className":1671,"code":3392,"language":1673,"meta":170,"style":170},[172,3744,3745],{"__ignoreMap":170},[249,3746,3747,3749,3751],{"class":251,"line":252},[249,3748,1828],{"class":925},[249,3750,3401],{"class":929},[249,3752,3404],{"class":929},[10,3754,3755],{},"Macのシステムデータが数百GBまで増えている場合は、Docker Desktopのデータが原因になっていないか確認してみてください。",[499,3757,3758],{},"html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html pre.shiki code .sbssI, html code.shiki .sbssI{--shiki-light:#F76D47;--shiki-default:#F78C6C;--shiki-dark:#F78C6C}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}",{"title":170,"searchDepth":258,"depth":258,"links":3760},[3761,3762,3763,3764,3765,3766,3767,3768],{"id":3200,"depth":258,"text":3201},{"id":3225,"depth":258,"text":3225},{"id":3385,"depth":258,"text":3386},{"id":3463,"depth":258,"text":3464},{"id":3506,"depth":258,"text":3507},{"id":3559,"depth":258,"text":3560},{"id":3645,"depth":258,"text":3645},{"id":465,"depth":258,"text":465},"Macの容量不足をきっかけに「システムデータ」が267GBまで肥大化した原因を調査し、DockerのBuild Cache、Image、DB Volumeを整理した手順を紹介します。",{},"\u002Farticles\u002F2026\u002Fresolve-mac-system-data-storage-shortage-with-docker","2026-08-10",{"title":3167,"description":3769},"articles\u002F2026\u002Fresolve-mac-system-data-storage-shortage-with-docker",[3776,2482],"Mac","\u002Fimages\u002Farticles\u002Fresolve-mac-system-data-storage-shortage-with-docker.png","KWp9gSbK5ytqT20G5ObWg3n5uQyKFKVp9aGSMNPqbgs",{"id":3780,"title":3781,"body":3782,"description":4475,"extension":517,"meta":4476,"navigation":261,"path":4477,"publishDate":4478,"published":261,"seo":4479,"stem":4480,"tags":4481,"thumbnail":4483,"updated":4478,"__hash__":4484},"articles\u002Farticles\u002F2024\u002Flately-learned-js-tip.md","最近学んだJavaScriptのTipsをアウトプット",{"type":7,"value":3783,"toc":4458},[3784,3786,3789,3792,3795,3844,3847,3850,3918,3935,3950,3964,3979,3982,3985,4021,4030,4038,4052,4078,4094,4097,4112,4115,4122,4179,4182,4189,4222,4232,4236,4245,4264,4267,4275,4313,4316,4340,4347,4353,4364,4392,4413,4416,4422,4425,4442,4444,4447,4456],[10,3785,12],{},[10,3787,3788],{},"今回は、最近学んだJavaScriptの小さなTipsとして、オブジェクトの分割代入とオプショナルチェーンを整理します。",[28,3790,3791],{"id":3791},"オブジェクトの分割代入",[10,3793,3794],{},"オブジェクトの分割代入を使うと、プロパティの値を取り出して変数へ代入できます。",[164,3796,3800],{"className":3797,"code":3798,"language":3799,"meta":170,"style":170},"language-javascript shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","const user = {\n  greeting: 'Hello',\n  farewell: 'Bye',\n}\n\nconst { greeting, farewell } = user\n\nconsole.log(greeting) \u002F\u002F 'Hello'\nconsole.log(farewell) \u002F\u002F 'Bye'\n","javascript",[172,3801,3802,3807,3812,3817,3821,3825,3830,3834,3839],{"__ignoreMap":170},[249,3803,3804],{"class":251,"line":252},[249,3805,3806],{},"const user = {\n",[249,3808,3809],{"class":251,"line":258},[249,3810,3811],{},"  greeting: 'Hello',\n",[249,3813,3814],{"class":251,"line":265},[249,3815,3816],{},"  farewell: 'Bye',\n",[249,3818,3819],{"class":251,"line":271},[249,3820,1124],{},[249,3822,3823],{"class":251,"line":277},[249,3824,262],{"emptyLinePlaceholder":261},[249,3826,3827],{"class":251,"line":283},[249,3828,3829],{},"const { greeting, farewell } = user\n",[249,3831,3832],{"class":251,"line":288},[249,3833,262],{"emptyLinePlaceholder":261},[249,3835,3836],{"class":251,"line":294},[249,3837,3838],{},"console.log(greeting) \u002F\u002F 'Hello'\n",[249,3840,3841],{"class":251,"line":300},[249,3842,3843],{},"console.log(farewell) \u002F\u002F 'Bye'\n",[404,3845,3846],{"id":3846},"ネストしたプロパティを取り出す",[10,3848,3849],{},"オブジェクトの中にオブジェクトがある場合は、データの構造に合わせて分割代入のパターンもネストできます。",[164,3851,3853],{"className":3797,"code":3852,"language":3799,"meta":170,"style":170},"const user = {\n  greeting: 'Hello',\n  message: {\n    farewell: 'Bye',\n  },\n}\n\nconst {\n  greeting,\n  message: { farewell },\n} = user\n\nconsole.log(greeting) \u002F\u002F 'Hello'\nconsole.log(farewell) \u002F\u002F 'Bye'\n",[172,3854,3855,3859,3863,3868,3873,3878,3882,3886,3891,3896,3901,3906,3910,3914],{"__ignoreMap":170},[249,3856,3857],{"class":251,"line":252},[249,3858,3806],{},[249,3860,3861],{"class":251,"line":258},[249,3862,3811],{},[249,3864,3865],{"class":251,"line":265},[249,3866,3867],{},"  message: {\n",[249,3869,3870],{"class":251,"line":271},[249,3871,3872],{},"    farewell: 'Bye',\n",[249,3874,3875],{"class":251,"line":277},[249,3876,3877],{},"  },\n",[249,3879,3880],{"class":251,"line":283},[249,3881,1124],{},[249,3883,3884],{"class":251,"line":288},[249,3885,262],{"emptyLinePlaceholder":261},[249,3887,3888],{"class":251,"line":294},[249,3889,3890],{},"const {\n",[249,3892,3893],{"class":251,"line":300},[249,3894,3895],{},"  greeting,\n",[249,3897,3898],{"class":251,"line":306},[249,3899,3900],{},"  message: { farewell },\n",[249,3902,3903],{"class":251,"line":311},[249,3904,3905],{},"} = user\n",[249,3907,3908],{"class":251,"line":317},[249,3909,262],{"emptyLinePlaceholder":261},[249,3911,3912],{"class":251,"line":323},[249,3913,3838],{},[249,3915,3916],{"class":251,"line":329},[249,3917,3843],{},[10,3919,3920,3921,3924,3925,144,3928,3931,3932,3934],{},"この例で作られる変数は",[172,3922,3923],{},"greeting","と",[172,3926,3927],{},"farewell",[172,3929,3930],{},"message","は、内側の",[172,3933,3927],{},"へたどるためのパターンとして使われているだけなので、変数として宣言されません。",[164,3936,3938],{"className":3797,"code":3937,"language":3799,"meta":170,"style":170},"console.log(message)\n\u002F\u002F ReferenceError: message is not defined\n",[172,3939,3940,3945],{"__ignoreMap":170},[249,3941,3942],{"class":251,"line":252},[249,3943,3944],{},"console.log(message)\n",[249,3946,3947],{"class":251,"line":258},[249,3948,3949],{},"\u002F\u002F ReferenceError: message is not defined\n",[2117,3951,3953],{"title":3952,"type":2120},"親オブジェクトも使いたい場合",[10,3954,3955,3957,3958,3960,3961,3963],{},[172,3956,3930],{},"自体と、その中の",[172,3959,3927],{},"を両方使いたい場合は、分割代入を分けるか、先に",[172,3962,3930],{},"を取り出してから再度分割代入します。",[164,3965,3967],{"className":3797,"code":3966,"language":3799,"meta":170,"style":170},"const { message } = user\nconst { farewell } = message\n",[172,3968,3969,3974],{"__ignoreMap":170},[249,3970,3971],{"class":251,"line":252},[249,3972,3973],{},"const { message } = user\n",[249,3975,3976],{"class":251,"line":258},[249,3977,3978],{},"const { farewell } = message\n",[404,3980,3981],{"id":3981},"プロパティ名とは異なる変数名で受け取る",[10,3983,3984],{},"コロンの右側へ名前を書くと、プロパティ名とは異なる変数名で値を受け取れます。",[164,3986,3988],{"className":3797,"code":3987,"language":3799,"meta":170,"style":170},"const user = {\n  name: 'Yuri',\n}\n\nconst { name: userName } = user\n\nconsole.log(userName) \u002F\u002F 'Yuri'\n",[172,3989,3990,3994,3999,4003,4007,4012,4016],{"__ignoreMap":170},[249,3991,3992],{"class":251,"line":252},[249,3993,3806],{},[249,3995,3996],{"class":251,"line":258},[249,3997,3998],{},"  name: 'Yuri',\n",[249,4000,4001],{"class":251,"line":265},[249,4002,1124],{},[249,4004,4005],{"class":251,"line":271},[249,4006,262],{"emptyLinePlaceholder":261},[249,4008,4009],{"class":251,"line":277},[249,4010,4011],{},"const { name: userName } = user\n",[249,4013,4014],{"class":251,"line":283},[249,4015,262],{"emptyLinePlaceholder":261},[249,4017,4018],{"class":251,"line":288},[249,4019,4020],{},"console.log(userName) \u002F\u002F 'Yuri'\n",[10,4022,4023,4024,4026,4027,144],{},"この場合も",[172,4025,2305],{},"という変数は作られず、作られるのは",[172,4028,4029],{},"userName",[28,4031,4033,4034,4037],{"id":4032},"オプショナルチェーン","オプショナルチェーン（",[172,4035,4036],{},"?.","）",[10,4039,4040,4041,4044,4045,4048,4049,4051],{},"オプショナルチェーンは、参照の途中にある値が",[172,4042,4043],{},"null","または",[172,4046,4047],{},"undefined","だった場合、エラーを発生させずに",[172,4050,4047],{},"を返す演算子です。",[164,4053,4055],{"className":3797,"code":4054,"language":3799,"meta":170,"style":170},"const user = {\n  name: 'Yuri',\n}\n\nconsole.log(user.profile?.hobby) \u002F\u002F undefined\n",[172,4056,4057,4061,4065,4069,4073],{"__ignoreMap":170},[249,4058,4059],{"class":251,"line":252},[249,4060,3806],{},[249,4062,4063],{"class":251,"line":258},[249,4064,3998],{},[249,4066,4067],{"class":251,"line":265},[249,4068,1124],{},[249,4070,4071],{"class":251,"line":271},[249,4072,262],{"emptyLinePlaceholder":261},[249,4074,4075],{"class":251,"line":277},[249,4076,4077],{},"console.log(user.profile?.hobby) \u002F\u002F undefined\n",[10,4079,4080,4083,4084,4086,4087,4089,4090,4093],{},[172,4081,4082],{},"user.profile","は",[172,4085,4047],{},"ですが、",[172,4088,4036],{},"を使っているため、その先の",[172,4091,4092],{},"hobby","へアクセスせず評価を終了します。",[10,4095,4096],{},"通常のプロパティアクセスではエラーになります。",[164,4098,4100],{"className":3797,"code":4099,"language":3799,"meta":170,"style":170},"console.log(user.profile.hobby)\n\u002F\u002F TypeError: Cannot read properties of undefined\n",[172,4101,4102,4107],{"__ignoreMap":170},[249,4103,4104],{"class":251,"line":252},[249,4105,4106],{},"console.log(user.profile.hobby)\n",[249,4108,4109],{"class":251,"line":258},[249,4110,4111],{},"\u002F\u002F TypeError: Cannot read properties of undefined\n",[404,4113,4114],{"id":4114},"配列の要素へアクセスする",[10,4116,4117,4118,4121],{},"角括弧によるアクセスでは、",[172,4119,4120],{},"?.[]","の形で使用します。",[164,4123,4125],{"className":3797,"code":4124,"language":3799,"meta":170,"style":170},"const items = [\n  { name: 'Item 1' },\n  { name: 'Item 2' },\n]\n\nconsole.log(items[1]?.name) \u002F\u002F 'Item 2'\nconsole.log(items[3]?.name) \u002F\u002F undefined\n\nconst emptyItems = undefined\n\nconsole.log(emptyItems?.[0]) \u002F\u002F undefined\n",[172,4126,4127,4132,4137,4142,4147,4151,4156,4161,4165,4170,4174],{"__ignoreMap":170},[249,4128,4129],{"class":251,"line":252},[249,4130,4131],{},"const items = [\n",[249,4133,4134],{"class":251,"line":258},[249,4135,4136],{},"  { name: 'Item 1' },\n",[249,4138,4139],{"class":251,"line":265},[249,4140,4141],{},"  { name: 'Item 2' },\n",[249,4143,4144],{"class":251,"line":271},[249,4145,4146],{},"]\n",[249,4148,4149],{"class":251,"line":277},[249,4150,262],{"emptyLinePlaceholder":261},[249,4152,4153],{"class":251,"line":283},[249,4154,4155],{},"console.log(items[1]?.name) \u002F\u002F 'Item 2'\n",[249,4157,4158],{"class":251,"line":288},[249,4159,4160],{},"console.log(items[3]?.name) \u002F\u002F undefined\n",[249,4162,4163],{"class":251,"line":294},[249,4164,262],{"emptyLinePlaceholder":261},[249,4166,4167],{"class":251,"line":300},[249,4168,4169],{},"const emptyItems = undefined\n",[249,4171,4172],{"class":251,"line":306},[249,4173,262],{"emptyLinePlaceholder":261},[249,4175,4176],{"class":251,"line":311},[249,4177,4178],{},"console.log(emptyItems?.[0]) \u002F\u002F undefined\n",[404,4180,4181],{"id":4181},"関数やメソッドを呼び出す",[10,4183,4184,4185,4188],{},"関数が存在するときだけ呼び出したい場合は、",[172,4186,4187],{},"?.()","を使用します。",[164,4190,4192],{"className":3797,"code":4191,"language":3799,"meta":170,"style":170},"const actions = {\n  greet: () => 'Hello',\n}\n\nconsole.log(actions.greet?.()) \u002F\u002F 'Hello'\nconsole.log(actions.sayGoodbye?.()) \u002F\u002F undefined\n",[172,4193,4194,4199,4204,4208,4212,4217],{"__ignoreMap":170},[249,4195,4196],{"class":251,"line":252},[249,4197,4198],{},"const actions = {\n",[249,4200,4201],{"class":251,"line":258},[249,4202,4203],{},"  greet: () => 'Hello',\n",[249,4205,4206],{"class":251,"line":265},[249,4207,1124],{},[249,4209,4210],{"class":251,"line":271},[249,4211,262],{"emptyLinePlaceholder":261},[249,4213,4214],{"class":251,"line":277},[249,4215,4216],{},"console.log(actions.greet?.()) \u002F\u002F 'Hello'\n",[249,4218,4219],{"class":251,"line":283},[249,4220,4221],{},"console.log(actions.sayGoodbye?.()) \u002F\u002F undefined\n",[10,4223,4224,4225,4228,4229,4231],{},"プロパティが存在していても、その値が関数でなければ",[172,4226,4227],{},"TypeError","になります。",[172,4230,4187],{},"は「呼び出し可能かどうか」まで確認するものではありません。",[404,4233,4235],{"id":4234},"dom要素へアクセスする","DOM要素へアクセスする",[10,4237,4238,4241,4242,4244],{},[172,4239,4240],{},"querySelector","は対象が見つからなかった場合に",[172,4243,4043],{},"を返します。要素が存在するときだけプロパティを参照したい場合にも利用できます。",[164,4246,4248],{"className":3797,"code":4247,"language":3799,"meta":170,"style":170},"const button = document.querySelector('.sample-button')\n\nconsole.log(button?.textContent) \u002F\u002F 要素がなければundefined\n",[172,4249,4250,4255,4259],{"__ignoreMap":170},[249,4251,4252],{"class":251,"line":252},[249,4253,4254],{},"const button = document.querySelector('.sample-button')\n",[249,4256,4257],{"class":251,"line":258},[249,4258,262],{"emptyLinePlaceholder":261},[249,4260,4261],{"class":251,"line":265},[249,4262,4263],{},"console.log(button?.textContent) \u002F\u002F 要素がなければundefined\n",[404,4265,4266],{"id":4266},"短絡評価される範囲",[10,4268,4269,4270,4044,4272,4274],{},"オプショナルチェーンでは、左側が",[172,4271,4043],{},[172,4273,4047],{},"の場合、そのチェーンの残りは評価されません。",[164,4276,4278],{"className":3797,"code":4277,"language":3799,"meta":170,"style":170},"let index = 0\nconst items = null\n\nconst item = items?.[index++]\n\nconsole.log(item) \u002F\u002F undefined\nconsole.log(index) \u002F\u002F 0\n",[172,4279,4280,4285,4290,4294,4299,4303,4308],{"__ignoreMap":170},[249,4281,4282],{"class":251,"line":252},[249,4283,4284],{},"let index = 0\n",[249,4286,4287],{"class":251,"line":258},[249,4288,4289],{},"const items = null\n",[249,4291,4292],{"class":251,"line":265},[249,4293,262],{"emptyLinePlaceholder":261},[249,4295,4296],{"class":251,"line":271},[249,4297,4298],{},"const item = items?.[index++]\n",[249,4300,4301],{"class":251,"line":277},[249,4302,262],{"emptyLinePlaceholder":261},[249,4304,4305],{"class":251,"line":283},[249,4306,4307],{},"console.log(item) \u002F\u002F undefined\n",[249,4309,4310],{"class":251,"line":288},[249,4311,4312],{},"console.log(index) \u002F\u002F 0\n",[10,4314,4315],{},"ただし、オプショナルチェーンが途切れた後のアクセスは保護されません。",[164,4317,4319],{"className":3797,"code":4318,"language":3799,"meta":170,"style":170},"const user = null\n\nuser?.profile.name \u002F\u002F undefined\n(user?.profile).name \u002F\u002F TypeError\n",[172,4320,4321,4326,4330,4335],{"__ignoreMap":170},[249,4322,4323],{"class":251,"line":252},[249,4324,4325],{},"const user = null\n",[249,4327,4328],{"class":251,"line":258},[249,4329,262],{"emptyLinePlaceholder":261},[249,4331,4332],{"class":251,"line":265},[249,4333,4334],{},"user?.profile.name \u002F\u002F undefined\n",[249,4336,4337],{"class":251,"line":271},[249,4338,4339],{},"(user?.profile).name \u002F\u002F TypeError\n",[10,4341,4342,4343,4346],{},"括弧で区切ると、その後の",[172,4344,4345],{},".name","は別のプロパティアクセスとして評価されます。",[28,4348,4350,4349],{"id":4349},"と組み合わせて既定値を設定する",[172,4351,4352],{},"??",[10,4354,4355,4356,4044,4358,4360,4361,4363],{},"オプショナルチェーンで取得した結果が",[172,4357,4043],{},[172,4359,4047],{},"だった場合、ヌル値合体演算子（",[172,4362,4352],{},"）で既定値を設定できます。",[164,4365,4367],{"className":3797,"code":4366,"language":3799,"meta":170,"style":170},"const user = {}\n\nconst hobby = user.profile?.hobby ?? '未設定'\n\nconsole.log(hobby) \u002F\u002F '未設定'\n",[172,4368,4369,4374,4378,4383,4387],{"__ignoreMap":170},[249,4370,4371],{"class":251,"line":252},[249,4372,4373],{},"const user = {}\n",[249,4375,4376],{"class":251,"line":258},[249,4377,262],{"emptyLinePlaceholder":261},[249,4379,4380],{"class":251,"line":265},[249,4381,4382],{},"const hobby = user.profile?.hobby ?? '未設定'\n",[249,4384,4385],{"class":251,"line":271},[249,4386,262],{"emptyLinePlaceholder":261},[249,4388,4389],{"class":251,"line":277},[249,4390,4391],{},"console.log(hobby) \u002F\u002F '未設定'\n",[10,4393,4394,4083,4397,4400,4401,4404,4405,4407,4408,4044,4410,4412],{},[172,4395,4396],{},"||",[172,4398,4399],{},"0","、空文字列、",[172,4402,4403],{},"false","も右側の値へ置き換えますが、",[172,4406,4352],{},"が右側を返すのは",[172,4409,4043],{},[172,4411,4047],{},"の場合だけです。",[28,4414,4415],{"id":4415},"オプショナルチェーンを使うときの注意点",[10,4417,4418,4419,4421],{},"オプショナルチェーンは条件分岐を簡潔にできますが、必須であるはずの値にまで使用すると、不具合を",[172,4420,4047],{},"として見逃す可能性があります。",[10,4423,4424],{},"次のように使い分けることが大切です。",[470,4426,4427,4433,4436],{},[473,4428,4429,4430,4432],{},"値が存在しないことを仕様として許容する場合は",[172,4431,4036],{},"を使う",[473,4434,4435],{},"値が必須の場合は明示的に確認し、存在しなければエラーとして扱う",[473,4437,4438,4439,4441],{},"取得結果に既定値が必要な場合は",[172,4440,4352],{},"を組み合わせる",[28,4443,465],{"id":465},[10,4445,4446],{},"ネストした分割代入を使うと、深い階層の値を簡潔に変数へ取り出せます。ただし、途中のプロパティ名がそのまま変数になるわけではありません。",[10,4448,4449,4450,4452,4453,4455],{},"オプショナルチェーンを使うと、",[172,4451,4043],{},"や",[172,4454,4047],{},"の可能性があるプロパティ、配列、関数へ安全にアクセスできます。便利さだけで多用せず、その値が本当に省略可能なのかを考えて使っていきたいです。",[499,4457,501],{},{"title":170,"searchDepth":258,"depth":258,"links":4459},[4460,4464,4471,4473,4474],{"id":3791,"depth":258,"text":3791,"children":4461},[4462,4463],{"id":3846,"depth":265,"text":3846},{"id":3981,"depth":265,"text":3981},{"id":4032,"depth":258,"text":4465,"children":4466},"オプショナルチェーン（?.）",[4467,4468,4469,4470],{"id":4114,"depth":265,"text":4114},{"id":4181,"depth":265,"text":4181},{"id":4234,"depth":265,"text":4235},{"id":4266,"depth":265,"text":4266},{"id":4349,"depth":258,"text":4472},"??と組み合わせて既定値を設定する",{"id":4415,"depth":258,"text":4415},{"id":465,"depth":258,"text":465},"JavaScriptのネストしたオブジェクトの分割代入とオプショナルチェーンについて、コード例と注意点を交えて整理します。",{},"\u002Farticles\u002F2024\u002Flately-learned-js-tip","2024-12-28",{"title":3781,"description":4475},"articles\u002F2024\u002Flately-learned-js-tip",[4482],"JavaScript","\u002Fimages\u002Farticles\u002Flately-learned-js-tip.png","Xi5F4LrgdP-cQxce9jEEPhpLiC086mIJfek4NR0cS3g",{"id":4486,"title":4487,"body":4488,"description":6124,"extension":517,"meta":6125,"navigation":261,"path":6126,"publishDate":6127,"published":261,"seo":6128,"stem":6129,"tags":6130,"thumbnail":6131,"updated":6127,"__hash__":6132},"articles\u002Farticles\u002F2024\u002Forganize-learned-from-todo.md","Todoアプリのハンズオンで学んだことを整理する",{"type":7,"value":4489,"toc":6095},[4490,4492,4501,4514,4517,4524,4533,4563,4566,4572,4574,4577,4580,4622,4625,4629,4632,4642,4645,4648,4654,4663,4865,4876,4879,4882,4983,4986,4989,5076,5079,5082,5110,5113,5116,5127,5272,5275,5278,5281,5284,5287,5295,5307,5375,5381,5386,5392,5435,5440,5443,5446,5512,5519,5522,5529,5642,5651,5658,5663,5722,5725,5728,5731,5825,5828,5834,5853,5863,5866,5869,5948,5955,5958,5961,6081,6084,6086,6089,6092],[10,4491,12],{},[10,4493,4494,4495,4500],{},"今回は「",[151,4496,4499],{"href":4497,"rel":4498},"https:\u002F\u002Fzenn.dev\u002Fsprout2000\u002Fbooks\u002F76a279bb90c3f3",[155],"React Hooks と TypeScript でつくる Todo PWA ～入門 React ハンズオン～","」を進める中で学んだことを、次の4つに分けて整理します。",[470,4502,4503,4506,4508,4511],{},[473,4504,4505],{},"HTML",[473,4507,4482],{},[473,4509,4510],{},"React",[473,4512,4513],{},"TypeScript",[28,4515,4505],{"id":4516},"html",[404,4518,4520,4523],{"id":4519},"autofocus属性",[172,4521,4522],{},"autofocus","属性",[10,4525,4526,4528,4529,4532],{},[172,4527,4522],{},"は、ページの読み込み時や",[172,4530,4531],{},"dialog","要素の表示時に、指定した要素へ自動的にフォーカスするための属性です。",[164,4534,4537],{"className":4535,"code":4536,"language":4516,"meta":170,"style":170},"language-html shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","\u003Cinput type=\"text\" autofocus>\n",[172,4538,4539],{"__ignoreMap":170},[249,4540,4541,4544,4547,4550,4552,4554,4556,4558,4561],{"class":251,"line":252},[249,4542,4543],{"class":1002},"\u003C",[249,4545,4546],{"class":1751},"input",[249,4548,4549],{"class":1085}," type",[249,4551,1177],{"class":1002},[249,4553,1088],{"class":1002},[249,4555,169],{"class":929},[249,4557,1088],{"class":1002},[249,4559,4560],{"class":1085}," autofocus",[249,4562,2992],{"class":1002},[10,4564,4565],{},"1つの文書やダイアログ内では、複数の要素へ指定しないようにします。複数指定した場合、最初に見つかった要素がフォーカスされます。",[2117,4567,4569],{"title":4568,"type":2367},"アクセシビリティへの配慮",[10,4570,4571],{},"ページを開いた直後にフォーカスが移動すると、スクリーンリーダー利用者やモバイル利用者を混乱させる場合があります。本当に自動フォーカスが必要かを検討して使用しましょう。",[28,4573,4482],{"id":3799},[404,4575,4576],{"id":4576},"オブジェクトのプロパティ名を動的にする",[10,4578,4579],{},"オブジェクトリテラルのプロパティ名を角括弧で囲むと、式の評価結果をプロパティ名として使用できます。これは計算プロパティ名と呼ばれます。",[164,4581,4583],{"className":3797,"code":4582,"language":3799,"meta":170,"style":170},"const key = 'sampleKey'\n\nconst sample = {\n  [key]: 'sampleValue',\n}\n\nconsole.log(sample) \u002F\u002F { sampleKey: 'sampleValue' }\nconsole.log(sample[key]) \u002F\u002F 'sampleValue'\n",[172,4584,4585,4590,4594,4599,4604,4608,4612,4617],{"__ignoreMap":170},[249,4586,4587],{"class":251,"line":252},[249,4588,4589],{},"const key = 'sampleKey'\n",[249,4591,4592],{"class":251,"line":258},[249,4593,262],{"emptyLinePlaceholder":261},[249,4595,4596],{"class":251,"line":265},[249,4597,4598],{},"const sample = {\n",[249,4600,4601],{"class":251,"line":271},[249,4602,4603],{},"  [key]: 'sampleValue',\n",[249,4605,4606],{"class":251,"line":277},[249,4607,1124],{},[249,4609,4610],{"class":251,"line":283},[249,4611,262],{"emptyLinePlaceholder":261},[249,4613,4614],{"class":251,"line":288},[249,4615,4616],{},"console.log(sample) \u002F\u002F { sampleKey: 'sampleValue' }\n",[249,4618,4619],{"class":251,"line":294},[249,4620,4621],{},"console.log(sample[key]) \u002F\u002F 'sampleValue'\n",[10,4623,4624],{},"入力項目の名前をキーとしてオブジェクトを更新する場合などに利用できます。",[404,4626,4628],{"id":4627},"tree-shaking","Tree Shaking",[10,4630,4631],{},"Tree Shakingは、利用されていないコードをビルド結果から取り除く最適化です。",[10,4633,4634,4635,3924,4638,4641],{},"主にバンドラーがES Modulesの",[172,4636,4637],{},"import",[172,4639,4640],{},"export","を静的に解析し、参照されていないエクスポートを出力対象から除外します。",[10,4643,4644],{},"実際に削除できる範囲は、バンドラーの設定やコードに副作用があるかどうかによって変わります。",[28,4646,4510],{"id":4647},"react",[404,4649,4651],{"id":4650},"createroot",[172,4652,4653],{},"createRoot",[10,4655,4656,4658,4659,4662],{},[172,4657,4653],{},"は、Reactが管理するルートをブラウザのDOM要素へ作成するAPIです。作成したルートの",[172,4660,4661],{},"render","メソッドへReact要素を渡して表示します。",[164,4664,4668],{"className":4665,"code":4666,"language":4667,"meta":170,"style":170},"language-tsx shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","import { StrictMode } from 'react'\nimport { createRoot } from 'react-dom\u002Fclient'\nimport App from '.\u002FApp'\n\nconst container = document.getElementById('root')\n\nif (!container) {\n  throw new Error('root要素が見つかりません')\n}\n\ncreateRoot(container).render(\n  \u003CStrictMode>\n    \u003CApp \u002F>\n  \u003C\u002FStrictMode>,\n)\n","tsx",[172,4669,4670,4693,4713,4730,4734,4766,4770,4786,4808,4812,4816,4830,4840,4851,4861],{"__ignoreMap":170},[249,4671,4672,4675,4678,4681,4684,4687,4689,4691],{"class":251,"line":252},[249,4673,4637],{"class":4674},"s7zQu",[249,4676,4677],{"class":1002}," {",[249,4679,4680],{"class":1173}," StrictMode",[249,4682,4683],{"class":1002}," }",[249,4685,4686],{"class":4674}," from",[249,4688,1003],{"class":1002},[249,4690,4647],{"class":929},[249,4692,1009],{"class":1002},[249,4694,4695,4697,4699,4702,4704,4706,4708,4711],{"class":251,"line":258},[249,4696,4637],{"class":4674},[249,4698,4677],{"class":1002},[249,4700,4701],{"class":1173}," createRoot",[249,4703,4683],{"class":1002},[249,4705,4686],{"class":4674},[249,4707,1003],{"class":1002},[249,4709,4710],{"class":929},"react-dom\u002Fclient",[249,4712,1009],{"class":1002},[249,4714,4715,4717,4720,4723,4725,4728],{"class":251,"line":265},[249,4716,4637],{"class":4674},[249,4718,4719],{"class":1173}," App ",[249,4721,4722],{"class":4674},"from",[249,4724,1003],{"class":1002},[249,4726,4727],{"class":929},".\u002FApp",[249,4729,1009],{"class":1002},[249,4731,4732],{"class":251,"line":271},[249,4733,262],{"emptyLinePlaceholder":261},[249,4735,4736,4739,4742,4744,4747,4749,4752,4755,4758,4761,4763],{"class":251,"line":277},[249,4737,4738],{"class":1085},"const",[249,4740,4741],{"class":1173}," container ",[249,4743,1177],{"class":1002},[249,4745,4746],{"class":1173}," document",[249,4748,1846],{"class":1002},[249,4750,4751],{"class":995},"getElementById",[249,4753,4754],{"class":1173},"(",[249,4756,4757],{"class":1002},"'",[249,4759,4760],{"class":929},"root",[249,4762,4757],{"class":1002},[249,4764,4765],{"class":1173},")\n",[249,4767,4768],{"class":251,"line":283},[249,4769,262],{"emptyLinePlaceholder":261},[249,4771,4772,4775,4778,4781,4784],{"class":251,"line":288},[249,4773,4774],{"class":4674},"if",[249,4776,4777],{"class":1173}," (",[249,4779,4780],{"class":1002},"!",[249,4782,4783],{"class":1173},"container) ",[249,4785,1077],{"class":1002},[249,4787,4788,4791,4794,4797,4799,4801,4804,4806],{"class":251,"line":294},[249,4789,4790],{"class":4674},"  throw",[249,4792,4793],{"class":1002}," new",[249,4795,4796],{"class":995}," Error",[249,4798,4754],{"class":1751},[249,4800,4757],{"class":1002},[249,4802,4803],{"class":929},"root要素が見つかりません",[249,4805,4757],{"class":1002},[249,4807,4765],{"class":1751},[249,4809,4810],{"class":251,"line":300},[249,4811,1124],{"class":1002},[249,4813,4814],{"class":251,"line":306},[249,4815,262],{"emptyLinePlaceholder":261},[249,4817,4818,4820,4823,4825,4827],{"class":251,"line":311},[249,4819,4653],{"class":995},[249,4821,4822],{"class":1173},"(container)",[249,4824,1846],{"class":1002},[249,4826,4661],{"class":995},[249,4828,4829],{"class":1173},"(\n",[249,4831,4832,4835,4838],{"class":251,"line":317},[249,4833,4834],{"class":1002},"  \u003C",[249,4836,4837],{"class":925},"StrictMode",[249,4839,2992],{"class":1002},[249,4841,4842,4845,4848],{"class":251,"line":323},[249,4843,4844],{"class":1002},"    \u003C",[249,4846,4847],{"class":925},"App",[249,4849,4850],{"class":1002}," \u002F>\n",[249,4852,4853,4856,4858],{"class":251,"line":329},[249,4854,4855],{"class":1002},"  \u003C\u002F",[249,4857,4837],{"class":925},[249,4859,4860],{"class":1002},">,\n",[249,4862,4863],{"class":251,"line":334},[249,4864,4765],{"class":1173},[10,4866,4867,4869,4870,4872,4873,4188],{},[172,4868,4653],{},"へ渡したDOM要素の内側はReactが管理します。サーバー側でReactが生成したHTMLを再利用する場合は、",[172,4871,4653],{},"ではなく",[172,4874,4875],{},"hydrateRoot",[404,4877,4878],{"id":4878},"stateを直接変更しない",[10,4880,4881],{},"Reactのstateに保存したオブジェクトや配列は、読み取り専用として扱います。値を直接変更せず、新しい値を作ってset関数へ渡します。",[164,4883,4885],{"className":4665,"code":4884,"language":4667,"meta":170,"style":170},"setTodos(currentTodos =>\n  currentTodos.map(todo =>\n    todo.id === id\n      ? { ...todo, completed: true }\n      : todo,\n  ),\n)\n",[172,4886,4887,4901,4918,4934,4961,4972,4979],{"__ignoreMap":170},[249,4888,4889,4892,4894,4898],{"class":251,"line":252},[249,4890,4891],{"class":995},"setTodos",[249,4893,4754],{"class":1173},[249,4895,4897],{"class":4896},"sHdIc","currentTodos",[249,4899,4900],{"class":1085}," =>\n",[249,4902,4903,4906,4908,4911,4913,4916],{"class":251,"line":258},[249,4904,4905],{"class":1173},"  currentTodos",[249,4907,1846],{"class":1002},[249,4909,4910],{"class":995},"map",[249,4912,4754],{"class":1173},[249,4914,4915],{"class":4896},"todo",[249,4917,4900],{"class":1085},[249,4919,4920,4923,4925,4928,4931],{"class":251,"line":265},[249,4921,4922],{"class":1173},"    todo",[249,4924,1846],{"class":1002},[249,4926,4927],{"class":1173},"id ",[249,4929,4930],{"class":1002},"===",[249,4932,4933],{"class":1173}," id\n",[249,4935,4936,4939,4941,4944,4946,4949,4952,4954,4958],{"class":251,"line":271},[249,4937,4938],{"class":1002},"      ?",[249,4940,4677],{"class":1002},[249,4942,4943],{"class":1002}," ...",[249,4945,4915],{"class":1173},[249,4947,4948],{"class":1002},",",[249,4950,4951],{"class":1751}," completed",[249,4953,1091],{"class":1002},[249,4955,4957],{"class":4956},"sfNiH"," true",[249,4959,4960],{"class":1002}," }\n",[249,4962,4963,4966,4969],{"class":251,"line":277},[249,4964,4965],{"class":1002},"      :",[249,4967,4968],{"class":1173}," todo",[249,4970,4971],{"class":1002},",\n",[249,4973,4974,4977],{"class":251,"line":283},[249,4975,4976],{"class":1173},"  )",[249,4978,4971],{"class":1002},[249,4980,4981],{"class":251,"line":288},[249,4982,4765],{"class":1173},[10,4984,4985],{},"配列を新しく作っても、その中にあるオブジェクトまでは自動的に複製されません。更新対象のオブジェクトもスプレッド構文などで新しく作る必要があります。",[10,4987,4988],{},"配列を更新する際は、次のように破壊的な操作を避けます。",[38,4990,4991,5004],{},[41,4992,4993],{},[44,4994,4995,4998,5001],{},[47,4996,4997],{},"操作",[47,4999,5000],{},"避けたい方法",[47,5002,5003],{},"利用する方法",[57,5005,5006,5025,5046,5060],{},[44,5007,5008,5011,5019],{},[62,5009,5010],{},"追加",[62,5012,5013,2561,5016],{},[172,5014,5015],{},"push",[172,5017,5018],{},"unshift",[62,5020,5021,5022],{},"スプレッド構文、",[172,5023,5024],{},"concat",[44,5026,5027,5030,5038],{},[62,5028,5029],{},"削除",[62,5031,5032,2561,5035],{},[172,5033,5034],{},"pop",[172,5036,5037],{},"splice",[62,5039,5040,2561,5043],{},[172,5041,5042],{},"filter",[172,5044,5045],{},"slice",[44,5047,5048,5051,5056],{},[62,5049,5050],{},"置換",[62,5052,5053,5054],{},"添字への代入、",[172,5055,5037],{},[62,5057,5058],{},[172,5059,4910],{},[44,5061,5062,5065,5071],{},[62,5063,5064],{},"並び替え",[62,5066,5067,5068],{},"元配列への",[172,5069,5070],{},"sort",[62,5072,5073,5074],{},"コピー後に",[172,5075,5070],{},[404,5077,5078],{"id":5078},"直前のstateを基に更新する",[10,5080,5081],{},"更新後のstateが更新前の値に依存する場合は、set関数へ値ではなく更新用の関数を渡します。",[164,5083,5085],{"className":4665,"code":5084,"language":4667,"meta":170,"style":170},"setCount(currentCount => currentCount + 1)\n",[172,5086,5087],{"__ignoreMap":170},[249,5088,5089,5092,5094,5097,5100,5103,5106,5108],{"class":251,"line":252},[249,5090,5091],{"class":995},"setCount",[249,5093,4754],{"class":1173},[249,5095,5096],{"class":4896},"currentCount",[249,5098,5099],{"class":1085}," =>",[249,5101,5102],{"class":1173}," currentCount ",[249,5104,5105],{"class":1002},"+",[249,5107,3246],{"class":1772},[249,5109,4765],{"class":1173},[10,5111,5112],{},"Reactはイベントハンドラーの処理をまとめてからstateを更新することがあります。更新用関数を使うことで、その時点の最新のstateを基に次の値を計算できます。",[404,5114,5115],{"id":5115},"イベントハンドラーの命名",[10,5117,5118,5119,5122,5123,5126],{},"イベントを処理する関数には",[172,5120,5121],{},"handle","、propsとして受け渡すイベントには",[172,5124,5125],{},"on","を付けると役割が伝わりやすくなります。",[164,5128,5130],{"className":4665,"code":5129,"language":4667,"meta":170,"style":170},"type TodoItemProps = {\n  onChange: (id: number) => void\n}\n\nfunction TodoItem({ onChange }: TodoItemProps) {\n  const handleChange = () => {\n    onChange(1)\n  }\n\n  return \u003Cinput type=\"checkbox\" onChange={handleChange} \u002F>\n}\n",[172,5131,5132,5145,5170,5174,5178,5201,5218,5229,5233,5237,5268],{"__ignoreMap":170},[249,5133,5134,5137,5140,5143],{"class":251,"line":252},[249,5135,5136],{"class":1085},"type",[249,5138,5139],{"class":925}," TodoItemProps",[249,5141,5142],{"class":1002}," =",[249,5144,1094],{"class":1002},[249,5146,5147,5150,5152,5154,5157,5159,5162,5165,5167],{"class":251,"line":258},[249,5148,5149],{"class":1751},"  onChange",[249,5151,1091],{"class":1002},[249,5153,4777],{"class":1002},[249,5155,5156],{"class":4896},"id",[249,5158,1091],{"class":1002},[249,5160,5161],{"class":925}," number",[249,5163,5164],{"class":1002},")",[249,5166,5099],{"class":1085},[249,5168,5169],{"class":925}," void\n",[249,5171,5172],{"class":251,"line":265},[249,5173,1124],{"class":1002},[249,5175,5176],{"class":251,"line":271},[249,5177,262],{"emptyLinePlaceholder":261},[249,5179,5180,5183,5186,5189,5192,5195,5197,5199],{"class":251,"line":277},[249,5181,5182],{"class":1085},"function",[249,5184,5185],{"class":995}," TodoItem",[249,5187,5188],{"class":1002},"({",[249,5190,5191],{"class":4896}," onChange",[249,5193,5194],{"class":1002}," }:",[249,5196,5139],{"class":925},[249,5198,5164],{"class":1002},[249,5200,1094],{"class":1002},[249,5202,5203,5206,5209,5211,5214,5216],{"class":251,"line":283},[249,5204,5205],{"class":1085},"  const",[249,5207,5208],{"class":1173}," handleChange",[249,5210,5142],{"class":1002},[249,5212,5213],{"class":1002}," ()",[249,5215,5099],{"class":1085},[249,5217,1094],{"class":1002},[249,5219,5220,5223,5225,5227],{"class":251,"line":288},[249,5221,5222],{"class":995},"    onChange",[249,5224,4754],{"class":1751},[249,5226,102],{"class":1772},[249,5228,4765],{"class":1751},[249,5230,5231],{"class":251,"line":294},[249,5232,1119],{"class":1002},[249,5234,5235],{"class":251,"line":300},[249,5236,262],{"emptyLinePlaceholder":261},[249,5238,5239,5242,5244,5246,5248,5250,5252,5255,5257,5259,5262,5265],{"class":251,"line":306},[249,5240,5241],{"class":4674},"  return",[249,5243,2984],{"class":1002},[249,5245,4546],{"class":1751},[249,5247,4549],{"class":1085},[249,5249,1177],{"class":1002},[249,5251,1088],{"class":1002},[249,5253,5254],{"class":929},"checkbox",[249,5256,1088],{"class":1002},[249,5258,5191],{"class":1085},[249,5260,5261],{"class":1002},"={",[249,5263,5264],{"class":1173},"handleChange",[249,5266,5267],{"class":1002},"} \u002F>\n",[249,5269,5270],{"class":251,"line":311},[249,5271,1124],{"class":1002},[10,5273,5274],{},"これはReactが強制する規則ではありませんが、一貫した命名はコードを読みやすくします。",[404,5276,5277],{"id":5277},"propsの分割代入",[10,5279,5280],{},"propsを分割代入すると記述は短くなりますが、変数がprops由来なのかコンポーネント内で定義されたものなのか分かりにくくなる場合があります。",[10,5282,5283],{},"コンポーネントが大きくなった場合は、変数名やコンポーネントの責務を見直し、値の出所を追いやすくすることが大切です。",[28,5285,4513],{"id":5286},"typescript",[404,5288,5290,3924,5293],{"id":5289},"documentgetelementbyidとnull",[172,5291,5292],{},"document.getElementById",[172,5294,4043],{},[10,5296,5297,5299,5300,5303,5304,5306],{},[172,5298,5292],{},"の戻り値は",[172,5301,5302],{},"HTMLElement | null","です。対象の要素が存在しない可能性があるため、利用前に",[172,5305,4043],{},"を確認します。",[164,5308,5311],{"className":5309,"code":5310,"language":5286,"meta":170,"style":170},"language-typescript shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","const container = document.getElementById('root')\n\nif (!container) {\n  throw new Error('root要素が見つかりません')\n}\n",[172,5312,5313,5337,5341,5353,5371],{"__ignoreMap":170},[249,5314,5315,5317,5319,5321,5323,5325,5327,5329,5331,5333,5335],{"class":251,"line":252},[249,5316,4738],{"class":1085},[249,5318,4741],{"class":1173},[249,5320,1177],{"class":1002},[249,5322,4746],{"class":1173},[249,5324,1846],{"class":1002},[249,5326,4751],{"class":995},[249,5328,4754],{"class":1173},[249,5330,4757],{"class":1002},[249,5332,4760],{"class":929},[249,5334,4757],{"class":1002},[249,5336,4765],{"class":1173},[249,5338,5339],{"class":251,"line":258},[249,5340,262],{"emptyLinePlaceholder":261},[249,5342,5343,5345,5347,5349,5351],{"class":251,"line":265},[249,5344,4774],{"class":4674},[249,5346,4777],{"class":1173},[249,5348,4780],{"class":1002},[249,5350,4783],{"class":1173},[249,5352,1077],{"class":1002},[249,5354,5355,5357,5359,5361,5363,5365,5367,5369],{"class":251,"line":271},[249,5356,4790],{"class":4674},[249,5358,4793],{"class":1002},[249,5360,4796],{"class":995},[249,5362,4754],{"class":1751},[249,5364,4757],{"class":1002},[249,5366,4803],{"class":929},[249,5368,4757],{"class":1002},[249,5370,4765],{"class":1751},[249,5372,5373],{"class":251,"line":277},[249,5374,1124],{"class":1002},[10,5376,5377,5378,5380],{},"Non-nullアサーション演算子（",[172,5379,4780],{},"）で確認を省略することもできますが、実行時に要素が必ず存在することをTypeScriptが保証するわけではありません。",[404,5382,5384],{"id":5383},"readonly",[172,5385,5383],{},[10,5387,5388,5389,5391],{},"プロパティへ",[172,5390,5383],{},"を指定すると、そのプロパティへの再代入を型チェックで防げます。",[164,5393,5395],{"className":5309,"code":5394,"language":5286,"meta":170,"style":170},"type Todo = {\n  readonly id: number\n  title: string\n}\n",[172,5396,5397,5408,5421,5431],{"__ignoreMap":170},[249,5398,5399,5401,5404,5406],{"class":251,"line":252},[249,5400,5136],{"class":1085},[249,5402,5403],{"class":925}," Todo",[249,5405,5142],{"class":1002},[249,5407,1094],{"class":1002},[249,5409,5410,5413,5416,5418],{"class":251,"line":258},[249,5411,5412],{"class":1085},"  readonly",[249,5414,5415],{"class":1751}," id",[249,5417,1091],{"class":1002},[249,5419,5420],{"class":925}," number\n",[249,5422,5423,5426,5428],{"class":251,"line":265},[249,5424,5425],{"class":1751},"  title",[249,5427,1091],{"class":1002},[249,5429,5430],{"class":925}," string\n",[249,5432,5433],{"class":251,"line":271},[249,5434,1124],{"class":1002},[10,5436,5437,5439],{},[172,5438,5383],{},"はコンパイル時の制約です。また、入れ子になったオブジェクトまで自動的に読み取り専用にするものではありません。",[404,5441,5442],{"id":5442},"イベントごとの型",[10,5444,5445],{},"Reactのイベントハンドラーでは、対象に応じたイベント型を利用できます。",[164,5447,5449],{"className":4665,"code":5448,"language":4667,"meta":170,"style":170},"function handleChange(event: React.ChangeEvent\u003CHTMLInputElement>) {\n  console.log(event.target.checked)\n}\n",[172,5450,5451,5482,5508],{"__ignoreMap":170},[249,5452,5453,5455,5457,5459,5462,5464,5467,5469,5472,5474,5477,5480],{"class":251,"line":252},[249,5454,5182],{"class":1085},[249,5456,5208],{"class":995},[249,5458,4754],{"class":1002},[249,5460,5461],{"class":4896},"event",[249,5463,1091],{"class":1002},[249,5465,5466],{"class":925}," React",[249,5468,1846],{"class":1002},[249,5470,5471],{"class":925},"ChangeEvent",[249,5473,4543],{"class":1002},[249,5475,5476],{"class":925},"HTMLInputElement",[249,5478,5479],{"class":1002},">)",[249,5481,1094],{"class":1002},[249,5483,5484,5487,5489,5492,5494,5496,5498,5501,5503,5506],{"class":251,"line":258},[249,5485,5486],{"class":1173},"  console",[249,5488,1846],{"class":1002},[249,5490,5491],{"class":995},"log",[249,5493,4754],{"class":1751},[249,5495,5461],{"class":1173},[249,5497,1846],{"class":1002},[249,5499,5500],{"class":1173},"target",[249,5502,1846],{"class":1002},[249,5504,5505],{"class":1173},"checked",[249,5507,4765],{"class":1751},[249,5509,5510],{"class":251,"line":265},[249,5511,1124],{"class":1002},[10,5513,5514,5515,5518],{},"イベント型だけでなく、",[172,5516,5517],{},"ChangeEventHandler\u003CHTMLInputElement>","のようなハンドラー全体の型を付ける方法もあります。",[404,5520,5521],{"id":5521},"ジェネリクスの型引数へ制約を付ける",[10,5523,5524,5525,5528],{},"型引数に",[172,5526,5527],{},"extends","を指定すると、ジェネリクスで受け取れる型に必要なプロパティを保証できます。",[164,5530,5532],{"className":5309,"code":5531,"language":5286,"meta":170,"style":170},"type Identifiable = {\n  id: number\n}\n\nfunction findById\u003CT extends Identifiable>(items: T[], id: number) {\n  return items.find(item => item.id === id)\n}\n",[172,5533,5534,5545,5554,5558,5562,5605,5638],{"__ignoreMap":170},[249,5535,5536,5538,5541,5543],{"class":251,"line":252},[249,5537,5136],{"class":1085},[249,5539,5540],{"class":925}," Identifiable",[249,5542,5142],{"class":1002},[249,5544,1094],{"class":1002},[249,5546,5547,5550,5552],{"class":251,"line":258},[249,5548,5549],{"class":1751},"  id",[249,5551,1091],{"class":1002},[249,5553,5420],{"class":925},[249,5555,5556],{"class":251,"line":265},[249,5557,1124],{"class":1002},[249,5559,5560],{"class":251,"line":271},[249,5561,262],{"emptyLinePlaceholder":261},[249,5563,5564,5566,5569,5571,5574,5577,5579,5582,5585,5587,5590,5593,5595,5597,5599,5601,5603],{"class":251,"line":277},[249,5565,5182],{"class":1085},[249,5567,5568],{"class":995}," findById",[249,5570,4543],{"class":1002},[249,5572,5573],{"class":925},"T",[249,5575,5576],{"class":1085}," extends",[249,5578,5540],{"class":925},[249,5580,5581],{"class":1002},">(",[249,5583,5584],{"class":4896},"items",[249,5586,1091],{"class":1002},[249,5588,5589],{"class":925}," T",[249,5591,5592],{"class":1173},"[]",[249,5594,4948],{"class":1002},[249,5596,5415],{"class":4896},[249,5598,1091],{"class":1002},[249,5600,5161],{"class":925},[249,5602,5164],{"class":1002},[249,5604,1094],{"class":1002},[249,5606,5607,5609,5612,5614,5617,5619,5622,5624,5627,5629,5631,5634,5636],{"class":251,"line":283},[249,5608,5241],{"class":4674},[249,5610,5611],{"class":1173}," items",[249,5613,1846],{"class":1002},[249,5615,5616],{"class":995},"find",[249,5618,4754],{"class":1751},[249,5620,5621],{"class":4896},"item",[249,5623,5099],{"class":1085},[249,5625,5626],{"class":1173}," item",[249,5628,1846],{"class":1002},[249,5630,5156],{"class":1173},[249,5632,5633],{"class":1002}," ===",[249,5635,5415],{"class":1173},[249,5637,4765],{"class":1751},[249,5639,5640],{"class":251,"line":288},[249,5641,1124],{"class":1002},[10,5643,5644,5645,5647,5648,5650],{},"制約がなければ",[172,5646,5573],{},"にどのような型が渡されるか分からないため、関数内で",[172,5649,5156],{},"へ安全にアクセスできません。",[404,5652,5654,5657],{"id":5653},"keyof型演算子",[172,5655,5656],{},"keyof","型演算子",[10,5659,5660,5662],{},[172,5661,5656],{},"は、オブジェクト型のプロパティ名からユニオン型を作る型演算子です。",[164,5664,5666],{"className":5309,"code":5665,"language":5286,"meta":170,"style":170},"type Todo = {\n  id: number\n  title: string\n}\n\ntype TodoKey = keyof Todo\n\u002F\u002F 'id' | 'title'\n",[172,5667,5668,5678,5686,5694,5698,5702,5717],{"__ignoreMap":170},[249,5669,5670,5672,5674,5676],{"class":251,"line":252},[249,5671,5136],{"class":1085},[249,5673,5403],{"class":925},[249,5675,5142],{"class":1002},[249,5677,1094],{"class":1002},[249,5679,5680,5682,5684],{"class":251,"line":258},[249,5681,5549],{"class":1751},[249,5683,1091],{"class":1002},[249,5685,5420],{"class":925},[249,5687,5688,5690,5692],{"class":251,"line":265},[249,5689,5425],{"class":1751},[249,5691,1091],{"class":1002},[249,5693,5430],{"class":925},[249,5695,5696],{"class":251,"line":271},[249,5697,1124],{"class":1002},[249,5699,5700],{"class":251,"line":277},[249,5701,262],{"emptyLinePlaceholder":261},[249,5703,5704,5706,5709,5711,5714],{"class":251,"line":283},[249,5705,5136],{"class":1085},[249,5707,5708],{"class":925}," TodoKey",[249,5710,5142],{"class":1002},[249,5712,5713],{"class":1002}," keyof",[249,5715,5716],{"class":925}," Todo\n",[249,5718,5719],{"class":251,"line":288},[249,5720,5721],{"class":2057},"\u002F\u002F 'id' | 'title'\n",[10,5723,5724],{},"プロパティを追加・削除したときにユニオン型を手作業で更新する必要がなくなり、型定義との不整合を防ぎやすくなります。",[404,5726,5727],{"id":5727},"インデックスアクセス型",[10,5729,5730],{},"インデックスアクセス型を使うと、オブジェクト型から特定のプロパティの型を取り出せます。",[164,5732,5734],{"className":5309,"code":5733,"language":5286,"meta":170,"style":170},"type Todo = {\n  id: number\n  title: string\n}\n\ntype TodoId = Todo['id']\n\u002F\u002F number\n\ntype TodoValue = Todo[keyof Todo]\n\u002F\u002F number | string\n",[172,5735,5736,5746,5754,5762,5766,5770,5792,5797,5801,5820],{"__ignoreMap":170},[249,5737,5738,5740,5742,5744],{"class":251,"line":252},[249,5739,5136],{"class":1085},[249,5741,5403],{"class":925},[249,5743,5142],{"class":1002},[249,5745,1094],{"class":1002},[249,5747,5748,5750,5752],{"class":251,"line":258},[249,5749,5549],{"class":1751},[249,5751,1091],{"class":1002},[249,5753,5420],{"class":925},[249,5755,5756,5758,5760],{"class":251,"line":265},[249,5757,5425],{"class":1751},[249,5759,1091],{"class":1002},[249,5761,5430],{"class":925},[249,5763,5764],{"class":251,"line":271},[249,5765,1124],{"class":1002},[249,5767,5768],{"class":251,"line":277},[249,5769,262],{"emptyLinePlaceholder":261},[249,5771,5772,5774,5777,5779,5781,5784,5786,5788,5790],{"class":251,"line":283},[249,5773,5136],{"class":1085},[249,5775,5776],{"class":925}," TodoId",[249,5778,5142],{"class":1002},[249,5780,5403],{"class":925},[249,5782,5783],{"class":1173},"[",[249,5785,4757],{"class":1002},[249,5787,5156],{"class":929},[249,5789,4757],{"class":1002},[249,5791,4146],{"class":1173},[249,5793,5794],{"class":251,"line":288},[249,5795,5796],{"class":2057},"\u002F\u002F number\n",[249,5798,5799],{"class":251,"line":294},[249,5800,262],{"emptyLinePlaceholder":261},[249,5802,5803,5805,5808,5810,5812,5814,5816,5818],{"class":251,"line":300},[249,5804,5136],{"class":1085},[249,5806,5807],{"class":925}," TodoValue",[249,5809,5142],{"class":1002},[249,5811,5403],{"class":925},[249,5813,5783],{"class":1173},[249,5815,5656],{"class":1002},[249,5817,5403],{"class":925},[249,5819,4146],{"class":1173},[249,5821,5822],{"class":251,"line":306},[249,5823,5824],{"class":2057},"\u002F\u002F number | string\n",[404,5826,5827],{"id":5827},"アンビエント宣言",[10,5829,5830,5833],{},[172,5831,5832],{},"declare","を使うと、実装が別の場所に存在する値や型をTypeScriptへ伝えられます。JavaScriptライブラリや実行環境が提供するグローバル変数の型を補う場合などに使用します。",[164,5835,5837],{"className":5309,"code":5836,"language":5286,"meta":170,"style":170},"declare const appVersion: string\n",[172,5838,5839],{"__ignoreMap":170},[249,5840,5841,5843,5846,5849,5851],{"class":251,"line":252},[249,5842,5832],{"class":1085},[249,5844,5845],{"class":1085}," const",[249,5847,5848],{"class":1173}," appVersion",[249,5850,1091],{"class":1002},[249,5852,5430],{"class":925},[10,5854,5855,5856,5859,5860,5862],{},"一般的には",[172,5857,5858],{},".d.ts","形式の型定義ファイルへ記述します。",[172,5861,5832],{},"は実行時の値を作成しないため、実体が存在しなければ実行時エラーになります。",[404,5864,5865],{"id":5865},"メソッドの型注釈",[10,5867,5868],{},"オブジェクト型のメソッドは、メソッド構文と関数プロパティ構文のどちらでも表現できます。",[164,5870,5872],{"className":5309,"code":5871,"language":5286,"meta":170,"style":170},"type Formatter = {\n  format(value: string): string\n}\n\ntype FormatterProperty = {\n  format: (value: string) => string\n}\n",[172,5873,5874,5885,5905,5909,5913,5924,5944],{"__ignoreMap":170},[249,5875,5876,5878,5881,5883],{"class":251,"line":252},[249,5877,5136],{"class":1085},[249,5879,5880],{"class":925}," Formatter",[249,5882,5142],{"class":1002},[249,5884,1094],{"class":1002},[249,5886,5887,5890,5892,5895,5897,5900,5903],{"class":251,"line":258},[249,5888,5889],{"class":1751},"  format",[249,5891,4754],{"class":1002},[249,5893,5894],{"class":4896},"value",[249,5896,1091],{"class":1002},[249,5898,5899],{"class":925}," string",[249,5901,5902],{"class":1002},"):",[249,5904,5430],{"class":925},[249,5906,5907],{"class":251,"line":265},[249,5908,1124],{"class":1002},[249,5910,5911],{"class":251,"line":271},[249,5912,262],{"emptyLinePlaceholder":261},[249,5914,5915,5917,5920,5922],{"class":251,"line":277},[249,5916,5136],{"class":1085},[249,5918,5919],{"class":925}," FormatterProperty",[249,5921,5142],{"class":1002},[249,5923,1094],{"class":1002},[249,5925,5926,5928,5930,5932,5934,5936,5938,5940,5942],{"class":251,"line":283},[249,5927,5889],{"class":1751},[249,5929,1091],{"class":1002},[249,5931,4777],{"class":1002},[249,5933,5894],{"class":4896},[249,5935,1091],{"class":1002},[249,5937,5899],{"class":925},[249,5939,5164],{"class":1002},[249,5941,5099],{"class":1085},[249,5943,5430],{"class":925},[249,5945,5946],{"class":251,"line":288},[249,5947,1124],{"class":1002},[10,5949,5950,5951,5954],{},"両者には、継承や",[172,5952,5953],{},"strictFunctionTypes","における引数型の扱いなどで違いがあります。プロジェクト内で意図に合った書き方へ揃えることが大切です。",[404,5956,5957],{"id":5957},"型ガード",[10,5959,5960],{},"型ガードは、実行時の確認を通して変数の型を絞り込む仕組みです。ユーザー定義型ガードでは、戻り値の型に型述語を指定します。",[164,5962,5964],{"className":5309,"code":5963,"language":5286,"meta":170,"style":170},"function isNumber(value: unknown): value is number {\n  return typeof value === 'number'\n}\n\nconst value: unknown = 10\n\nif (isNumber(value)) {\n  console.log(value.toFixed(2))\n}\n",[172,5965,5966,5994,6012,6016,6020,6035,6039,6053,6077],{"__ignoreMap":170},[249,5967,5968,5970,5973,5975,5977,5979,5982,5984,5987,5990,5992],{"class":251,"line":252},[249,5969,5182],{"class":1085},[249,5971,5972],{"class":995}," isNumber",[249,5974,4754],{"class":1002},[249,5976,5894],{"class":4896},[249,5978,1091],{"class":1002},[249,5980,5981],{"class":925}," unknown",[249,5983,5902],{"class":1002},[249,5985,5986],{"class":4896}," value",[249,5988,5989],{"class":1002}," is",[249,5991,5161],{"class":925},[249,5993,1094],{"class":1002},[249,5995,5996,5998,6001,6003,6005,6007,6010],{"class":251,"line":258},[249,5997,5241],{"class":4674},[249,5999,6000],{"class":1002}," typeof",[249,6002,5986],{"class":1173},[249,6004,5633],{"class":1002},[249,6006,1003],{"class":1002},[249,6008,6009],{"class":929},"number",[249,6011,1009],{"class":1002},[249,6013,6014],{"class":251,"line":265},[249,6015,1124],{"class":1002},[249,6017,6018],{"class":251,"line":271},[249,6019,262],{"emptyLinePlaceholder":261},[249,6021,6022,6024,6026,6028,6030,6032],{"class":251,"line":277},[249,6023,4738],{"class":1085},[249,6025,5986],{"class":1173},[249,6027,1091],{"class":1002},[249,6029,5981],{"class":925},[249,6031,5142],{"class":1002},[249,6033,6034],{"class":1772}," 10\n",[249,6036,6037],{"class":251,"line":283},[249,6038,262],{"emptyLinePlaceholder":261},[249,6040,6041,6043,6045,6048,6051],{"class":251,"line":288},[249,6042,4774],{"class":4674},[249,6044,4777],{"class":1173},[249,6046,6047],{"class":995},"isNumber",[249,6049,6050],{"class":1173},"(value)) ",[249,6052,1077],{"class":1002},[249,6054,6055,6057,6059,6061,6063,6065,6067,6070,6072,6074],{"class":251,"line":294},[249,6056,5486],{"class":1173},[249,6058,1846],{"class":1002},[249,6060,5491],{"class":995},[249,6062,4754],{"class":1751},[249,6064,5894],{"class":1173},[249,6066,1846],{"class":1002},[249,6068,6069],{"class":995},"toFixed",[249,6071,4754],{"class":1751},[249,6073,112],{"class":1772},[249,6075,6076],{"class":1751},"))\n",[249,6078,6079],{"class":251,"line":300},[249,6080,1124],{"class":1002},[10,6082,6083],{},"APIレスポンスなど外部から受け取った値は、型アサーションで決めつけるのではなく、実行時に検証してから利用すると安全です。",[28,6085,465],{"id":465},[10,6087,6088],{},"Todoアプリの実装を通して、HTML属性の使い方からReactのstate更新、TypeScriptの型操作まで、幅広い内容を学べました。",[10,6090,6091],{},"個々の構文を覚えるだけでなく、「なぜその書き方が必要なのか」を実際のアプリ開発と結び付けて理解することが大切だと感じました。",[499,6093,6094],{},"html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .swJcz, html code.shiki .swJcz{--shiki-light:#E53935;--shiki-default:#F07178;--shiki-dark:#F07178}html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html pre.shiki code .s7zQu, html code.shiki .s7zQu{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#89DDFF;--shiki-default-font-style:italic;--shiki-dark:#89DDFF;--shiki-dark-font-style:italic}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .sHdIc, html code.shiki .sHdIc{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#EEFFFF;--shiki-default-font-style:italic;--shiki-dark:#BABED8;--shiki-dark-font-style:italic}html pre.shiki code .sfNiH, html code.shiki .sfNiH{--shiki-light:#FF5370;--shiki-default:#FF9CAC;--shiki-dark:#FF9CAC}html pre.shiki code .sbssI, html code.shiki .sbssI{--shiki-light:#F76D47;--shiki-default:#F78C6C;--shiki-dark:#F78C6C}html pre.shiki code .sHwdD, html code.shiki .sHwdD{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#546E7A;--shiki-default-font-style:italic;--shiki-dark:#676E95;--shiki-dark-font-style:italic}",{"title":170,"searchDepth":258,"depth":258,"links":6096},[6097,6100,6104,6111,6123],{"id":4516,"depth":258,"text":4505,"children":6098},[6099],{"id":4519,"depth":265,"text":4519},{"id":3799,"depth":258,"text":4482,"children":6101},[6102,6103],{"id":4576,"depth":265,"text":4576},{"id":4627,"depth":265,"text":4628},{"id":4647,"depth":258,"text":4510,"children":6105},[6106,6107,6108,6109,6110],{"id":4650,"depth":265,"text":4653},{"id":4878,"depth":265,"text":4878},{"id":5078,"depth":265,"text":5078},{"id":5115,"depth":265,"text":5115},{"id":5277,"depth":265,"text":5277},{"id":5286,"depth":258,"text":4513,"children":6112},[6113,6115,6116,6117,6118,6119,6120,6121,6122],{"id":5289,"depth":265,"text":6114},"document.getElementByIdとnull",{"id":5383,"depth":265,"text":5383},{"id":5442,"depth":265,"text":5442},{"id":5521,"depth":265,"text":5521},{"id":5653,"depth":265,"text":5653},{"id":5727,"depth":265,"text":5727},{"id":5827,"depth":265,"text":5827},{"id":5865,"depth":265,"text":5865},{"id":5957,"depth":265,"text":5957},{"id":465,"depth":258,"text":465},"React HooksとTypeScriptでTodoアプリを作るハンズオンを通して学んだ、HTML、JavaScript、React、TypeScriptのポイントを整理します。",{},"\u002Farticles\u002F2024\u002Forganize-learned-from-todo","2024-12-23",{"title":4487,"description":6124},"articles\u002F2024\u002Forganize-learned-from-todo",[4510,4513],"\u002Fimages\u002Farticles\u002Forganize-learned-from-todo.png","ic1Do2Gie9Gb4WmAmZ2IL55ETNgmySMOwEHT_s3q0bk",{"id":6134,"title":6135,"body":6136,"description":6611,"extension":517,"meta":6612,"navigation":261,"path":6613,"publishDate":6614,"published":261,"seo":6615,"stem":6616,"tags":6617,"thumbnail":6619,"updated":6614,"__hash__":6620},"articles\u002Farticles\u002F2024\u002Fdescribe-webstorage-indexeddb.md","Web StorageとIndexedDBについて整理する",{"type":7,"value":6137,"toc":6601},[6138,6140,6143,6153,6156,6159,6162,6165,6247,6250,6255,6258,6286,6297,6348,6351,6354,6362,6381,6384,6387,6390,6393,6396,6498,6501,6515,6518,6521,6524,6548,6554,6557,6560,6567,6570,6573,6588,6591,6593,6596,6599],[10,6139,12],{},[10,6141,6142],{},"Todoアプリを作った際にIndexedDBを利用したのですが、ブラウザにデータを保存する方法としてはWeb Storageもあります。",[10,6144,6145,6146,2561,6149,6152],{},"今回は、",[172,6147,6148],{},"localStorage",[172,6150,6151],{},"sessionStorage","、IndexedDBの特徴と使い分けを整理します。",[28,6154,6155],{"id":6155},"ブラウザにデータを保存する仕組み",[10,6157,6158],{},"Web StorageとIndexedDBは、どちらもブラウザ側にデータを保存するためのWeb APIです。",[10,6160,6161],{},"保存したデータが自動的にサーバーへ送信されることはなく、同一オリジンの制約を受けます。ただし、保存容量やデータが削除される条件はブラウザや利用状況によって異なるため、永続性を前提にしすぎないことが大切です。",[10,6163,6164],{},"主な違いは次のとおりです。",[38,6166,6167,6180],{},[41,6168,6169],{},[44,6170,6171,6173,6175,6177],{},[47,6172,834],{},[47,6174,6148],{},[47,6176,6151],{},[47,6178,6179],{},"IndexedDB",[57,6181,6182,6195,6207,6220,6233],{},[44,6183,6184,6187,6190,6192],{},[62,6185,6186],{},"保存形式",[62,6188,6189],{},"文字列のキーバリュー",[62,6191,6189],{},[62,6193,6194],{},"オブジェクトやBlobなど",[44,6196,6197,6199,6202,6204],{},[62,6198,64],{},[62,6200,6201],{},"同期",[62,6203,6201],{},[62,6205,6206],{},"非同期",[44,6208,6209,6212,6215,6218],{},[62,6210,6211],{},"データの範囲",[62,6213,6214],{},"同一オリジン",[62,6216,6217],{},"同一オリジンかつタブ単位",[62,6219,6214],{},[44,6221,6222,6225,6228,6231],{},[62,6223,6224],{},"データの寿命",[62,6226,6227],{},"明示的に削除されるまで",[62,6229,6230],{},"タブを閉じるまで",[62,6232,6227],{},[44,6234,6235,6238,6241,6244],{},[62,6236,6237],{},"得意な用途",[62,6239,6240],{},"小さな設定値",[62,6242,6243],{},"一時的な入力状態",[62,6245,6246],{},"大量・構造化データ",[28,6248,6148],{"id":6249},"localstorage",[10,6251,6252,6254],{},[172,6253,6148],{},"は、文字列をキーバリュー形式で保存する同期APIです。",[10,6256,6257],{},"ブラウザやタブを閉じてもデータが残るため、テーマや表示設定など、小さく単純なデータの保存に向いています。",[164,6259,6261],{"className":3797,"code":6260,"language":3799,"meta":170,"style":170},"localStorage.setItem('theme', 'dark')\n\nconst theme = localStorage.getItem('theme')\n\nlocalStorage.removeItem('theme')\n",[172,6262,6263,6268,6272,6277,6281],{"__ignoreMap":170},[249,6264,6265],{"class":251,"line":252},[249,6266,6267],{},"localStorage.setItem('theme', 'dark')\n",[249,6269,6270],{"class":251,"line":258},[249,6271,262],{"emptyLinePlaceholder":261},[249,6273,6274],{"class":251,"line":265},[249,6275,6276],{},"const theme = localStorage.getItem('theme')\n",[249,6278,6279],{"class":251,"line":271},[249,6280,262],{"emptyLinePlaceholder":261},[249,6282,6283],{"class":251,"line":277},[249,6284,6285],{},"localStorage.removeItem('theme')\n",[10,6287,6288,6289,6292,6293,6296],{},"値は文字列として保存されます。オブジェクトを扱う場合は、保存時に",[172,6290,6291],{},"JSON.stringify()","、取得時に",[172,6294,6295],{},"JSON.parse()","が必要です。",[164,6298,6300],{"className":3797,"code":6299,"language":3799,"meta":170,"style":170},"const settings = {\n  theme: 'dark',\n  fontSize: 16,\n}\n\nlocalStorage.setItem('settings', JSON.stringify(settings))\n\nconst storedSettings = JSON.parse(\n  localStorage.getItem('settings') ?? '{}',\n)\n",[172,6301,6302,6307,6312,6317,6321,6325,6330,6334,6339,6344],{"__ignoreMap":170},[249,6303,6304],{"class":251,"line":252},[249,6305,6306],{},"const settings = {\n",[249,6308,6309],{"class":251,"line":258},[249,6310,6311],{},"  theme: 'dark',\n",[249,6313,6314],{"class":251,"line":265},[249,6315,6316],{},"  fontSize: 16,\n",[249,6318,6319],{"class":251,"line":271},[249,6320,1124],{},[249,6322,6323],{"class":251,"line":277},[249,6324,262],{"emptyLinePlaceholder":261},[249,6326,6327],{"class":251,"line":283},[249,6328,6329],{},"localStorage.setItem('settings', JSON.stringify(settings))\n",[249,6331,6332],{"class":251,"line":288},[249,6333,262],{"emptyLinePlaceholder":261},[249,6335,6336],{"class":251,"line":294},[249,6337,6338],{},"const storedSettings = JSON.parse(\n",[249,6340,6341],{"class":251,"line":300},[249,6342,6343],{},"  localStorage.getItem('settings') ?? '{}',\n",[249,6345,6346],{"class":251,"line":306},[249,6347,4765],{},[10,6349,6350],{},"同期APIのため、大きなデータを頻繁に読み書きするとメインスレッドを塞ぐ可能性があります。",[28,6352,6151],{"id":6353},"sessionstorage",[10,6355,6356,6358,6359,6361],{},[172,6357,6151],{},"も、文字列をキーバリュー形式で保存する同期APIです。基本的な操作方法は",[172,6360,6148],{},"と同じです。",[164,6363,6365],{"className":3797,"code":6364,"language":3799,"meta":170,"style":170},"sessionStorage.setItem('draft', '入力途中の内容')\n\nconst draft = sessionStorage.getItem('draft')\n",[172,6366,6367,6372,6376],{"__ignoreMap":170},[249,6368,6369],{"class":251,"line":252},[249,6370,6371],{},"sessionStorage.setItem('draft', '入力途中の内容')\n",[249,6373,6374],{"class":251,"line":258},[249,6375,262],{"emptyLinePlaceholder":261},[249,6377,6378],{"class":251,"line":265},[249,6379,6380],{},"const draft = sessionStorage.getItem('draft')\n",[10,6382,6383],{},"ページを再読み込みしてもデータは残りますが、保存領域はタブごとのページセッションに分かれ、タブを閉じるとデータも削除されます。",[10,6385,6386],{},"そのため、フォームの入力途中の状態や、画面遷移中だけ保持したい一時的な情報に向いています。",[28,6388,6179],{"id":6389},"indexeddb",[10,6391,6392],{},"IndexedDBは、大量の構造化データをブラウザへ保存するための非同期APIです。",[10,6394,6395],{},"JavaScriptのオブジェクトだけでなく、ファイルやBlobなども保存できます。また、オブジェクトストア、インデックス、トランザクションを利用できるため、検索や更新を伴うデータ管理に向いています。",[164,6397,6399],{"className":3797,"code":6398,"language":3799,"meta":170,"style":170},"const request = indexedDB.open('todo-app', 1)\n\nrequest.onupgradeneeded = () => {\n  const database = request.result\n\n  if (!database.objectStoreNames.contains('todos')) {\n    database.createObjectStore('todos', {\n      keyPath: 'id',\n      autoIncrement: true,\n    })\n  }\n}\n\nrequest.onsuccess = () => {\n  const database = request.result\n  const transaction = database.transaction('todos', 'readwrite')\n  const todos = transaction.objectStore('todos')\n\n  todos.add({ title: '記事を書く', completed: false })\n}\n",[172,6400,6401,6406,6410,6415,6420,6424,6429,6434,6439,6444,6449,6453,6457,6461,6466,6470,6476,6482,6487,6493],{"__ignoreMap":170},[249,6402,6403],{"class":251,"line":252},[249,6404,6405],{},"const request = indexedDB.open('todo-app', 1)\n",[249,6407,6408],{"class":251,"line":258},[249,6409,262],{"emptyLinePlaceholder":261},[249,6411,6412],{"class":251,"line":265},[249,6413,6414],{},"request.onupgradeneeded = () => {\n",[249,6416,6417],{"class":251,"line":271},[249,6418,6419],{},"  const database = request.result\n",[249,6421,6422],{"class":251,"line":277},[249,6423,262],{"emptyLinePlaceholder":261},[249,6425,6426],{"class":251,"line":283},[249,6427,6428],{},"  if (!database.objectStoreNames.contains('todos')) {\n",[249,6430,6431],{"class":251,"line":288},[249,6432,6433],{},"    database.createObjectStore('todos', {\n",[249,6435,6436],{"class":251,"line":294},[249,6437,6438],{},"      keyPath: 'id',\n",[249,6440,6441],{"class":251,"line":300},[249,6442,6443],{},"      autoIncrement: true,\n",[249,6445,6446],{"class":251,"line":306},[249,6447,6448],{},"    })\n",[249,6450,6451],{"class":251,"line":311},[249,6452,1119],{},[249,6454,6455],{"class":251,"line":317},[249,6456,1124],{},[249,6458,6459],{"class":251,"line":323},[249,6460,262],{"emptyLinePlaceholder":261},[249,6462,6463],{"class":251,"line":329},[249,6464,6465],{},"request.onsuccess = () => {\n",[249,6467,6468],{"class":251,"line":334},[249,6469,6419],{},[249,6471,6473],{"class":251,"line":6472},16,[249,6474,6475],{},"  const transaction = database.transaction('todos', 'readwrite')\n",[249,6477,6479],{"class":251,"line":6478},17,[249,6480,6481],{},"  const todos = transaction.objectStore('todos')\n",[249,6483,6485],{"class":251,"line":6484},18,[249,6486,262],{"emptyLinePlaceholder":261},[249,6488,6490],{"class":251,"line":6489},19,[249,6491,6492],{},"  todos.add({ title: '記事を書く', completed: false })\n",[249,6494,6496],{"class":251,"line":6495},20,[249,6497,1124],{},[10,6499,6500],{},"Web Storageよりも扱う概念は多いものの、次のような用途で力を発揮します。",[470,6502,6503,6506,6509,6512],{},[473,6504,6505],{},"オフラインでも利用するアプリ",[473,6507,6508],{},"Todoやメモなど、件数が増えるデータ",[473,6510,6511],{},"検索や並び替えにインデックスを使いたいデータ",[473,6513,6514],{},"画像やファイルを含むデータ",[28,6516,6517],{"id":6517},"保存容量とデータの削除",[10,6519,6520],{},"ブラウザストレージの容量は、特定の数値をどの環境でも保証できるものではありません。ブラウザ、端末の空き容量、ユーザー設定などによって変わります。",[10,6522,6523],{},"利用状況はStorage APIから概算できます。",[164,6525,6527],{"className":3797,"code":6526,"language":3799,"meta":170,"style":170},"const estimate = await navigator.storage.estimate()\n\nconsole.log(estimate.usage)\nconsole.log(estimate.quota)\n",[172,6528,6529,6534,6538,6543],{"__ignoreMap":170},[249,6530,6531],{"class":251,"line":252},[249,6532,6533],{},"const estimate = await navigator.storage.estimate()\n",[249,6535,6536],{"class":251,"line":258},[249,6537,262],{"emptyLinePlaceholder":261},[249,6539,6540],{"class":251,"line":265},[249,6541,6542],{},"console.log(estimate.usage)\n",[249,6544,6545],{"class":251,"line":271},[249,6546,6547],{},"console.log(estimate.quota)\n",[2117,6549,6551],{"title":6550,"type":2367},"ブラウザストレージを唯一の保存先にしない",[10,6552,6553],{},"保存したデータは、ユーザーによるサイトデータの削除や、ブラウザのストレージ管理によって失われる場合があります。失われると困るデータはサーバーにも保存しましょう。",[28,6555,6556],{"id":6556},"セキュリティ上の注意",[10,6558,6559],{},"Web StorageとIndexedDBは、認証された同一オリジンのJavaScriptからアクセスできます。",[2117,6561,6564],{"title":6562,"type":6563},"機密情報の保存に注意する","warning",[10,6565,6566],{},"クロスサイトスクリプティング（XSS）が発生すると、保存内容を読み取られる可能性があります。アクセストークンや個人情報などの機密情報を、安易に保存しないようにしましょう。",[28,6568,6569],{"id":6569},"どれを選ぶか",[10,6571,6572],{},"選び方を簡単にまとめると、次のようになります。",[470,6574,6575,6580,6585],{},[473,6576,6577,6578],{},"小さな設定をブラウザを閉じた後も残したい場合は",[172,6579,6148],{},[473,6581,6582,6583],{},"タブを開いている間だけ一時的に残したい場合は",[172,6584,6151],{},[473,6586,6587],{},"大量のデータや構造化データを非同期で扱いたい場合はIndexedDB",[10,6589,6590],{},"Web Storageは手軽ですが、同期APIであり文字列しか保存できません。データ量が増えるアプリや、検索・更新を伴うデータにはIndexedDBを検討するとよいでしょう。",[28,6592,465],{"id":465},[10,6594,6595],{},"Web StorageとIndexedDBは、どちらもブラウザ側へデータを保存できますが、得意な用途が異なります。",[10,6597,6598],{},"保存するデータの量や形式だけでなく、同期処理による影響、データを保持する期間、失われた場合の影響まで考えて選ぶことが大切です。",[499,6600,501],{},{"title":170,"searchDepth":258,"depth":258,"links":6602},[6603,6604,6605,6606,6607,6608,6609,6610],{"id":6155,"depth":258,"text":6155},{"id":6249,"depth":258,"text":6148},{"id":6353,"depth":258,"text":6151},{"id":6389,"depth":258,"text":6179},{"id":6517,"depth":258,"text":6517},{"id":6556,"depth":258,"text":6556},{"id":6569,"depth":258,"text":6569},{"id":465,"depth":258,"text":465},"localStorage、sessionStorage、IndexedDBの違いを、保存形式、同期・非同期、データの寿命、用途から整理します。",{},"\u002Farticles\u002F2024\u002Fdescribe-webstorage-indexeddb","2024-12-22",{"title":6135,"description":6611},"articles\u002F2024\u002Fdescribe-webstorage-indexeddb",[6618,6179],"Web Storage","\u002Fimages\u002Farticles\u002Fdescribe-webstorage-indexeddb.png","3W_8UP01CjjLWIG3qOQhJB7e1YiLPuYONYyx_372v98",{"id":6622,"title":6623,"body":6624,"description":7099,"extension":517,"meta":7100,"navigation":261,"path":7101,"publishDate":7102,"published":261,"seo":7103,"stem":7104,"tags":7105,"thumbnail":7106,"updated":7102,"__hash__":7107},"articles\u002Farticles\u002F2024\u002Flearn-javascript-eventloop-from-runtime.md","JavaScriptのランタイム構成からイベントループを学ぶ",{"type":7,"value":6625,"toc":7089},[6626,6628,6637,6640,6644,6647,6650,6653,6670,6672,6675,6678,6742,6745,6778,6781,6784,6787,6790,6804,6807,6850,6853,6855,6858,6861,6875,6880,6883,6885,6888,6913,6916,6919,6921,6924,6927,6944,6947,6950,7025,7028,7034,7044,7053,7055,7075,7078,7087],[10,6627,12],{},[10,6629,6630,6631,6636],{},"今回は、JavaScriptのイベントループについて、動画「",[151,6632,6635],{"href":6633,"rel":6634},"https:\u002F\u002Fwww.youtube.com\u002Fwatch?v=eiC58R16hb8",[155],"JavaScript Visualized - Event Loop, Web APIs, (Micro)task Queue","」で学んだ内容を整理します。",[10,6638,6639],{},"ブラウザでJavaScriptがどのように同期処理と非同期処理を扱っているのか、ランタイムを構成する要素から確認していきます。",[28,6641,6643],{"id":6642},"javascriptエンジンとホスト環境","JavaScriptエンジンとホスト環境",[10,6645,6646],{},"ブラウザでJavaScriptを実行するためには、JavaScriptエンジンとブラウザというホスト環境が連携します。",[10,6648,6649],{},"JavaScriptエンジンはコードを解析・実行し、ブラウザはタイマー、ネットワーク通信、DOMイベントなどの環境固有の機能を提供します。",[10,6651,6652],{},"イベントループを理解するうえでは、次の要素を押さえておくと全体像が見えやすくなります。",[470,6654,6655,6658,6661,6664,6667],{},[473,6656,6657],{},"コールスタック",[473,6659,6660],{},"Web APIs",[473,6662,6663],{},"タスクキュー",[473,6665,6666],{},"マイクロタスクキュー",[473,6668,6669],{},"イベントループ",[28,6671,6657],{"id":6657},[10,6673,6674],{},"コールスタックは、実行中の関数や実行コンテキストを管理するスタックです。",[10,6676,6677],{},"後から追加されたものが先に取り出される、後入れ先出し（LIFO）の構造になっています。",[164,6679,6681],{"className":3797,"code":6680,"language":3799,"meta":170,"style":170},"function a() {\n  console.log('a')\n}\n\nfunction b() {\n  a()\n}\n\nfunction c() {\n  b()\n}\n\nc()\n",[172,6682,6683,6688,6693,6697,6701,6706,6711,6715,6719,6724,6729,6733,6737],{"__ignoreMap":170},[249,6684,6685],{"class":251,"line":252},[249,6686,6687],{},"function a() {\n",[249,6689,6690],{"class":251,"line":258},[249,6691,6692],{},"  console.log('a')\n",[249,6694,6695],{"class":251,"line":265},[249,6696,1124],{},[249,6698,6699],{"class":251,"line":271},[249,6700,262],{"emptyLinePlaceholder":261},[249,6702,6703],{"class":251,"line":277},[249,6704,6705],{},"function b() {\n",[249,6707,6708],{"class":251,"line":283},[249,6709,6710],{},"  a()\n",[249,6712,6713],{"class":251,"line":288},[249,6714,1124],{},[249,6716,6717],{"class":251,"line":294},[249,6718,262],{"emptyLinePlaceholder":261},[249,6720,6721],{"class":251,"line":300},[249,6722,6723],{},"function c() {\n",[249,6725,6726],{"class":251,"line":306},[249,6727,6728],{},"  b()\n",[249,6730,6731],{"class":251,"line":311},[249,6732,1124],{},[249,6734,6735],{"class":251,"line":317},[249,6736,262],{"emptyLinePlaceholder":261},[249,6738,6739],{"class":251,"line":323},[249,6740,6741],{},"c()\n",[10,6743,6744],{},"このコードは、次の流れで実行されます。",[638,6746,6747,6753,6762,6769],{},[473,6748,6749,6752],{},[172,6750,6751],{},"c()"," がスタックへ追加される",[473,6754,6755,6757,6758,6761],{},[172,6756,6751],{}," から呼ばれた ",[172,6759,6760],{},"b()"," が追加される",[473,6763,6764,6757,6766,6761],{},[172,6765,6760],{},[172,6767,6768],{},"a()",[473,6770,6771,2561,6773,2561,6775,6777],{},[172,6772,6768],{},[172,6774,6760],{},[172,6776,6751],{}," の順に処理を終えてスタックから取り除かれる",[10,6779,6780],{},"1つの長い同期処理がコールスタックを占有すると、その処理が終わるまでクリックや描画など、同じスレッド上のほかの処理を進められません。",[28,6782,6660],{"id":6783},"web-apis",[10,6785,6786],{},"Web APIsは、ブラウザというホスト環境が提供する機能です。",[10,6788,6789],{},"代表的なものには、次があります。",[470,6791,6792,6795,6798,6801],{},[473,6793,6794],{},"Fetch API",[473,6796,6797],{},"タイマー",[473,6799,6800],{},"Geolocation API",[473,6802,6803],{},"DOMイベント",[10,6805,6806],{},"JavaScriptからこれらの非同期APIを呼び出すと、ブラウザ側でタイマーの計測やネットワーク通信などが進みます。JavaScriptはその完了を待ってコールスタックを占有し続ける必要がないため、別のコードを実行できます。",[164,6808,6810],{"className":3797,"code":6809,"language":3799,"meta":170,"style":170},"navigator.geolocation.getCurrentPosition(\n  position => console.log(position),\n  error => console.error(error),\n)\n\nfetch('https:\u002F\u002Fexample.com\u002Fapi\u002Fdata')\n  .then(response => response.json())\n  .then(data => console.log(data))\n",[172,6811,6812,6817,6822,6827,6831,6835,6840,6845],{"__ignoreMap":170},[249,6813,6814],{"class":251,"line":252},[249,6815,6816],{},"navigator.geolocation.getCurrentPosition(\n",[249,6818,6819],{"class":251,"line":258},[249,6820,6821],{},"  position => console.log(position),\n",[249,6823,6824],{"class":251,"line":265},[249,6825,6826],{},"  error => console.error(error),\n",[249,6828,6829],{"class":251,"line":271},[249,6830,4765],{},[249,6832,6833],{"class":251,"line":277},[249,6834,262],{"emptyLinePlaceholder":261},[249,6836,6837],{"class":251,"line":283},[249,6838,6839],{},"fetch('https:\u002F\u002Fexample.com\u002Fapi\u002Fdata')\n",[249,6841,6842],{"class":251,"line":288},[249,6843,6844],{},"  .then(response => response.json())\n",[249,6846,6847],{"class":251,"line":294},[249,6848,6849],{},"  .then(data => console.log(data))\n",[10,6851,6852],{},"APIの処理が完了しても、コールバックがその場ですぐに実行されるとは限りません。実行可能になった処理は、タスクやマイクロタスクとしてキューへ登録されます。",[28,6854,6663],{"id":6663},[10,6856,6857],{},"タスクキューには、タイマーやイベントなどをきっかけに実行可能になったタスクが並びます。",[10,6859,6860],{},"代表的な例は次のとおりです。",[470,6862,6863,6869,6872],{},[473,6864,6865,6868],{},[172,6866,6867],{},"setTimeout()"," のコールバック",[473,6870,6871],{},"ユーザー操作のイベントハンドラー",[473,6873,6874],{},"メッセージイベント",[10,6876,6877,6879],{},[172,6878,6867],{}," に指定する時間は、コールバックが必ずその時間後に実行されるという意味ではありません。指定時間を経過したあとにタスクとして実行可能になるまでの最低待機時間です。",[10,6881,6882],{},"コールスタックや先に処理されるタスクが残っていれば、実際の実行はさらに遅くなります。",[28,6884,6666],{"id":6666},[10,6886,6887],{},"マイクロタスクキューには、主に次の処理が登録されます。",[470,6889,6890,6902,6908],{},[473,6891,6892,6893,2561,6896,2561,6899],{},"Promiseの ",[172,6894,6895],{},"then()",[172,6897,6898],{},"catch()",[172,6900,6901],{},"finally()",[473,6903,6904,6907],{},[172,6905,6906],{},"queueMicrotask()"," に渡したコールバック",[473,6909,6910,6868],{},[172,6911,6912],{},"MutationObserver",[10,6914,6915],{},"現在のタスクと同期処理が終わってコールスタックが空になると、次のタスクへ進む前にマイクロタスクキューが空になるまで処理されます。",[10,6917,6918],{},"マイクロタスクの実行中に新しいマイクロタスクが追加された場合も、同じタイミングで続けて処理されます。そのため、マイクロタスクを追加し続ける処理は、次のタスクや画面描画を遅らせる可能性があります。",[28,6920,6669],{"id":6669},[10,6922,6923],{},"イベントループは、コールスタックと各キューの状態を見ながら、実行する処理を選び続けます。",[10,6925,6926],{},"ブラウザ上の流れを単純化すると、次のようになります。",[638,6928,6929,6932,6935,6938,6941],{},[473,6930,6931],{},"1つのタスクを実行する",[473,6933,6934],{},"コールスタック上の同期処理を最後まで実行する",[473,6936,6937],{},"マイクロタスクキューを空になるまで処理する",[473,6939,6940],{},"必要に応じて画面を描画する",[473,6942,6943],{},"次のタスクへ進む",[28,6945,6946],{"id":6946},"コードで実行順を確認する",[10,6948,6949],{},"タスクとマイクロタスクの実行順を、コードで確認してみましょう。",[164,6951,6953],{"className":3797,"code":6952,"language":3799,"meta":170,"style":170},"console.log('start')\n\nsetTimeout(() => {\n  console.log('timeout')\n}, 0)\n\nPromise.resolve().then(() => {\n  console.log('promise')\n})\n\nqueueMicrotask(() => {\n  console.log('microtask')\n})\n\nconsole.log('end')\n",[172,6954,6955,6960,6964,6969,6974,6979,6983,6988,6993,6998,7002,7007,7012,7016,7020],{"__ignoreMap":170},[249,6956,6957],{"class":251,"line":252},[249,6958,6959],{},"console.log('start')\n",[249,6961,6962],{"class":251,"line":258},[249,6963,262],{"emptyLinePlaceholder":261},[249,6965,6966],{"class":251,"line":265},[249,6967,6968],{},"setTimeout(() => {\n",[249,6970,6971],{"class":251,"line":271},[249,6972,6973],{},"  console.log('timeout')\n",[249,6975,6976],{"class":251,"line":277},[249,6977,6978],{},"}, 0)\n",[249,6980,6981],{"class":251,"line":283},[249,6982,262],{"emptyLinePlaceholder":261},[249,6984,6985],{"class":251,"line":288},[249,6986,6987],{},"Promise.resolve().then(() => {\n",[249,6989,6990],{"class":251,"line":294},[249,6991,6992],{},"  console.log('promise')\n",[249,6994,6995],{"class":251,"line":300},[249,6996,6997],{},"})\n",[249,6999,7000],{"class":251,"line":306},[249,7001,262],{"emptyLinePlaceholder":261},[249,7003,7004],{"class":251,"line":311},[249,7005,7006],{},"queueMicrotask(() => {\n",[249,7008,7009],{"class":251,"line":317},[249,7010,7011],{},"  console.log('microtask')\n",[249,7013,7014],{"class":251,"line":323},[249,7015,6997],{},[249,7017,7018],{"class":251,"line":329},[249,7019,262],{"emptyLinePlaceholder":261},[249,7021,7022],{"class":251,"line":334},[249,7023,7024],{},"console.log('end')\n",[10,7026,7027],{},"出力順は次のようになります。",[164,7029,7032],{"className":7030,"code":7031,"language":169,"meta":170},[167],"start\nend\npromise\nmicrotask\ntimeout\n",[172,7033,7031],{"__ignoreMap":170},[10,7035,7036,7037,2557,7040,7043],{},"まず同期処理の ",[172,7038,7039],{},"start",[172,7041,7042],{},"end"," が出力されます。",[10,7045,7046,7047,7049,7050,7052],{},"続いて、登録された順にPromiseのコールバックと ",[172,7048,6906],{}," のコールバックがマイクロタスクとして実行されます。マイクロタスクキューが空になったあと、",[172,7051,6867],{}," のコールバックが次のタスクとして実行されます。",[28,7054,465],{"id":465},[470,7056,7057,7060,7063,7066,7069,7072],{},[473,7058,7059],{},"コールスタックは、実行中の関数をLIFOで管理する",[473,7061,7062],{},"ブラウザは、タイマーやネットワーク通信などのWeb APIsを提供する",[473,7064,7065],{},"タイマーやイベントのコールバックなどは、タスクとしてキューへ登録される",[473,7067,7068],{},"Promiseのコールバックなどは、マイクロタスクとして登録される",[473,7070,7071],{},"現在のタスクが完了すると、次のタスクより先にマイクロタスクが処理される",[473,7073,7074],{},"長い同期処理や増え続けるマイクロタスクは、画面の応答を遅らせる可能性がある",[10,7076,7077],{},"非同期処理の実行順で迷ったときは、「現在の同期処理」「マイクロタスク」「次のタスク」の順に分けて考えると整理しやすくなります。",[10,7079,7080,7081,7086],{},"より詳しい実行モデルは、",[151,7082,7085],{"href":7083,"rel":7084},"https:\u002F\u002Fdeveloper.mozilla.org\u002Fja\u002Fdocs\u002FWeb\u002FJavaScript\u002FReference\u002FExecution_model",[155],"MDNのJavaScript実行モデル","も参考になります。",[499,7088,501],{},{"title":170,"searchDepth":258,"depth":258,"links":7090},[7091,7092,7093,7094,7095,7096,7097,7098],{"id":6642,"depth":258,"text":6643},{"id":6657,"depth":258,"text":6657},{"id":6783,"depth":258,"text":6660},{"id":6663,"depth":258,"text":6663},{"id":6666,"depth":258,"text":6666},{"id":6669,"depth":258,"text":6669},{"id":6946,"depth":258,"text":6946},{"id":465,"depth":258,"text":465},"ブラウザのJavaScriptランタイムを構成するコールスタック、Web APIs、タスクキュー、マイクロタスクキューとイベントループの関係を整理します。",{},"\u002Farticles\u002F2024\u002Flearn-javascript-eventloop-from-runtime","2024-11-25",{"title":6623,"description":7099},"articles\u002F2024\u002Flearn-javascript-eventloop-from-runtime",[4482],"\u002Fimages\u002Farticles\u002Flearn-javascript-eventloop-from-runtime.png","BcnDDE_gLqK4tjYoVA9O89QF7-dNwS-6lyORZ07cH5g",{"id":7109,"title":7110,"body":7111,"description":7526,"extension":517,"meta":7527,"navigation":261,"path":7528,"publishDate":7529,"published":261,"seo":7530,"stem":7531,"tags":7532,"thumbnail":7533,"updated":7529,"__hash__":7534},"articles\u002Farticles\u002F2024\u002Fhow-to-use-javascript-built-in-objects.md","JavaScriptのビルトインオブジェクトのメソッドをどう使うか",{"type":7,"value":7112,"toc":7518},[7113,7115,7118,7121,7125,7128,7140,7149,7153,7163,7190,7207,7215,7218,7225,7265,7276,7284,7296,7320,7324,7331,7369,7375,7380,7401,7404,7413,7451,7461,7479,7481,7513,7516],[10,7114,12],{},[10,7116,7117],{},"今回は、プロジェクトで「なるほど」と思った、JavaScriptのビルトインオブジェクトのメソッドの使い方を紹介します。",[10,7119,7120],{},"具体的には、オブジェクトが自身のプロパティを持っているか、安全に確認する方法です。仕組みを知っておくと、オブジェクトに同名のメソッドが定義されている場合も意図した判定ができます。",[28,7122,7124],{"id":7123},"ビルトインオブジェクトってなに","「ビルトインオブジェクト」ってなに？",[10,7126,7127],{},"ビルトインオブジェクトは「組み込みオブジェクト」とも呼ばれ、JavaScriptの実行環境にあらかじめ用意されているオブジェクトです。",[10,7129,7130,2561,7133,2561,7136,7139],{},[172,7131,7132],{},"Object",[172,7134,7135],{},"Array",[172,7137,7138],{},"String"," など、さまざまな種類があります。",[10,7141,7142,7143,7148],{},"詳しくは、",[151,7144,7147],{"href":7145,"rel":7146},"https:\u002F\u002Fdeveloper.mozilla.org\u002Fja\u002Fdocs\u002FWeb\u002FJavaScript\u002FReference\u002FGlobal_Objects",[155],"MDNの標準組み込みオブジェクト","を参照してください。",[28,7150,7152],{"id":7151},"hasownpropertyをインスタンスから呼び出す","hasOwnPropertyをインスタンスから呼び出す",[10,7154,7155,7156,7158,7159,7162],{},"まずは、オブジェクト自身が ",[172,7157,2305],{}," プロパティを持っているか、",[172,7160,7161],{},"hasOwnProperty()"," で確認してみます。",[164,7164,7166],{"className":3797,"code":7165,"language":3799,"meta":170,"style":170},"const obj = {\n  name: 'Yuri',\n}\n\nobj.hasOwnProperty('name') \u002F\u002F true\n",[172,7167,7168,7173,7177,7181,7185],{"__ignoreMap":170},[249,7169,7170],{"class":251,"line":252},[249,7171,7172],{},"const obj = {\n",[249,7174,7175],{"class":251,"line":258},[249,7176,3998],{},[249,7178,7179],{"class":251,"line":265},[249,7180,1124],{},[249,7182,7183],{"class":251,"line":271},[249,7184,262],{"emptyLinePlaceholder":261},[249,7186,7187],{"class":251,"line":277},[249,7188,7189],{},"obj.hasOwnProperty('name') \u002F\u002F true\n",[10,7191,7192,7193,7196,7197,7200,7201,7203,7204,7206],{},"オブジェクトリテラルで作成した ",[172,7194,7195],{},"obj"," は、通常 ",[172,7198,7199],{},"Object.prototype"," を継承しています。そのため、",[172,7202,7199],{}," に定義されている ",[172,7205,7161],{}," を呼び出せます。",[10,7208,7209,7210,7086],{},"プロトタイプ継承については、",[151,7211,7214],{"href":7212,"rel":7213},"https:\u002F\u002Fja.javascript.info\u002Fprototype-inheritance",[155],"JavaScript.infoのプロトタイプ継承",[28,7216,7217],{"id":7217},"インスタンスから呼び出す場合の問題",[10,7219,7220,7221,7224],{},"では、オブジェクト自身が ",[172,7222,7223],{},"hasOwnProperty"," という同名のメソッドを持っていたらどうなるでしょうか。",[164,7226,7228],{"className":3797,"code":7227,"language":3799,"meta":170,"style":170},"const obj = {\n  name: 'Yuri',\n  hasOwnProperty() {\n    console.log('Hello')\n  },\n}\n\nobj.hasOwnProperty('name') \u002F\u002F 「Hello」と出力される\n",[172,7229,7230,7234,7238,7243,7248,7252,7256,7260],{"__ignoreMap":170},[249,7231,7232],{"class":251,"line":252},[249,7233,7172],{},[249,7235,7236],{"class":251,"line":258},[249,7237,3998],{},[249,7239,7240],{"class":251,"line":265},[249,7241,7242],{},"  hasOwnProperty() {\n",[249,7244,7245],{"class":251,"line":271},[249,7246,7247],{},"    console.log('Hello')\n",[249,7249,7250],{"class":251,"line":277},[249,7251,3877],{},[249,7253,7254],{"class":251,"line":283},[249,7255,1124],{},[249,7257,7258],{"class":251,"line":288},[249,7259,262],{"emptyLinePlaceholder":261},[249,7261,7262],{"class":251,"line":294},[249,7263,7264],{},"obj.hasOwnProperty('name') \u002F\u002F 「Hello」と出力される\n",[10,7266,7267,7268,7271,7272,7275],{},"先ほどは ",[172,7269,7270],{},"true"," を返していた呼び出しが、今度は ",[172,7273,7274],{},"Hello"," を出力しました。",[10,7277,7278,7280,7281,7283],{},[172,7279,7195],{}," 自身の ",[172,7282,7223],{}," が、プロトタイプから継承した同名メソッドよりも優先されたためです。外部から受け取ったオブジェクトなど、自分で構造を完全に管理できない値では、インスタンスから直接呼び出す方法は意図しない結果につながる可能性があります。",[10,7285,357,7286,7289,7290,7292,7293,7295],{},[172,7287,7288],{},"Object.create(null)"," で作ったオブジェクトは ",[172,7291,7199],{}," を継承しないため、そもそも ",[172,7294,7161],{}," を持っていません。",[164,7297,7299],{"className":3797,"code":7298,"language":3799,"meta":170,"style":170},"const obj = Object.create(null)\nobj.name = 'Yuri'\n\nobj.hasOwnProperty('name') \u002F\u002F TypeError\n",[172,7300,7301,7306,7311,7315],{"__ignoreMap":170},[249,7302,7303],{"class":251,"line":252},[249,7304,7305],{},"const obj = Object.create(null)\n",[249,7307,7308],{"class":251,"line":258},[249,7309,7310],{},"obj.name = 'Yuri'\n",[249,7312,7313],{"class":251,"line":265},[249,7314,262],{"emptyLinePlaceholder":261},[249,7316,7317],{"class":251,"line":271},[249,7318,7319],{},"obj.hasOwnProperty('name') \u002F\u002F TypeError\n",[28,7321,7323],{"id":7322},"objecthasownを使う","Object.hasOwnを使う",[10,7325,7326,7327,7330],{},"現在は、オブジェクト自身のプロパティを調べる場合、静的メソッドの ",[172,7328,7329],{},"Object.hasOwn()"," を使うと簡潔です。",[164,7332,7334],{"className":3797,"code":7333,"language":3799,"meta":170,"style":170},"const obj = {\n  name: 'Yuri',\n  hasOwnProperty() {\n    console.log('Hello')\n  },\n}\n\nObject.hasOwn(obj, 'name') \u002F\u002F true\n",[172,7335,7336,7340,7344,7348,7352,7356,7360,7364],{"__ignoreMap":170},[249,7337,7338],{"class":251,"line":252},[249,7339,7172],{},[249,7341,7342],{"class":251,"line":258},[249,7343,3998],{},[249,7345,7346],{"class":251,"line":265},[249,7347,7242],{},[249,7349,7350],{"class":251,"line":271},[249,7351,7247],{},[249,7353,7354],{"class":251,"line":277},[249,7355,3877],{},[249,7357,7358],{"class":251,"line":283},[249,7359,1124],{},[249,7361,7362],{"class":251,"line":288},[249,7363,262],{"emptyLinePlaceholder":261},[249,7365,7366],{"class":251,"line":294},[249,7367,7368],{},"Object.hasOwn(obj, 'name') \u002F\u002F true\n",[10,7370,7371,7372,7374],{},"第1引数に調べたいオブジェクト、第2引数にプロパティ名を渡します。対象のオブジェクトに同名の ",[172,7373,7223],{}," が定義されていても影響を受けません。",[10,7376,7377,7379],{},[172,7378,7288],{}," で作ったオブジェクトにも使用できます。",[164,7381,7383],{"className":3797,"code":7382,"language":3799,"meta":170,"style":170},"const obj = Object.create(null)\nobj.name = 'Yuri'\n\nObject.hasOwn(obj, 'name') \u002F\u002F true\n",[172,7384,7385,7389,7393,7397],{"__ignoreMap":170},[249,7386,7387],{"class":251,"line":252},[249,7388,7305],{},[249,7390,7391],{"class":251,"line":258},[249,7392,7310],{},[249,7394,7395],{"class":251,"line":265},[249,7396,262],{"emptyLinePlaceholder":261},[249,7398,7399],{"class":251,"line":271},[249,7400,7368],{},[28,7402,7403],{"id":7403},"古い実行環境も考慮する場合",[10,7405,7406,7408,7409,7412],{},[172,7407,7329],{}," を利用できない古い実行環境まで考慮する場合は、",[172,7410,7411],{},"Object.prototype.hasOwnProperty.call()"," という書き方もできます。",[164,7414,7416],{"className":3797,"code":7415,"language":3799,"meta":170,"style":170},"const obj = {\n  name: 'Yuri',\n  hasOwnProperty() {\n    console.log('Hello')\n  },\n}\n\nObject.prototype.hasOwnProperty.call(obj, 'name') \u002F\u002F true\n",[172,7417,7418,7422,7426,7430,7434,7438,7442,7446],{"__ignoreMap":170},[249,7419,7420],{"class":251,"line":252},[249,7421,7172],{},[249,7423,7424],{"class":251,"line":258},[249,7425,3998],{},[249,7427,7428],{"class":251,"line":265},[249,7429,7242],{},[249,7431,7432],{"class":251,"line":271},[249,7433,7247],{},[249,7435,7436],{"class":251,"line":277},[249,7437,3877],{},[249,7439,7440],{"class":251,"line":283},[249,7441,1124],{},[249,7443,7444],{"class":251,"line":288},[249,7445,262],{"emptyLinePlaceholder":261},[249,7447,7448],{"class":251,"line":294},[249,7449,7450],{},"Object.prototype.hasOwnProperty.call(obj, 'name') \u002F\u002F true\n",[10,7452,7453,7456,7457,7460],{},[172,7454,7455],{},"call()"," の第1引数に ",[172,7458,7459],{},"this"," として扱うオブジェクトを指定し、それ以降の引数を元のメソッドへ渡しています。",[10,7462,7463,7464,7466,7467,7469,7470,7472,7473,7475,7476,7478],{},"この例では ",[172,7465,7199],{}," が持つ本来の ",[172,7468,7161],{}," を直接取得し、",[172,7471,7195],{}," を ",[172,7474,7459],{}," として呼び出しています。そのため、",[172,7477,7195],{}," 自身に定義された同名メソッドの影響を受けません。",[28,7480,465],{"id":465},[470,7482,7483,7489,7492,7499,7506],{},[473,7484,7485,7486,7488],{},"オブジェクトリテラルは通常、",[172,7487,7199],{}," のメソッドを継承する",[473,7490,7491],{},"オブジェクト自身が同名メソッドを持つと、継承したメソッドは隠される",[473,7493,7494,7289,7496,7498],{},[172,7495,7288],{},[172,7497,7161],{}," を継承しない",[473,7500,7501,7502,7505],{},"自身のプロパティを確認する場合は、基本的に ",[172,7503,7504],{},"Object.hasOwn(obj, property)"," を使う",[473,7507,7508,7509,7512],{},"古い実行環境も考慮する場合は、",[172,7510,7511],{},"Object.prototype.hasOwnProperty.call(obj, property)"," を使える",[10,7514,7515],{},"オブジェクトの出所や構造を完全には把握できない場合も、インスタンスの同名メソッドに依存しない呼び出し方を選ぶと安全です。",[499,7517,501],{},{"title":170,"searchDepth":258,"depth":258,"links":7519},[7520,7521,7522,7523,7524,7525],{"id":7123,"depth":258,"text":7124},{"id":7151,"depth":258,"text":7152},{"id":7217,"depth":258,"text":7217},{"id":7322,"depth":258,"text":7323},{"id":7403,"depth":258,"text":7403},{"id":465,"depth":258,"text":465},"JavaScriptでオブジェクト自身のプロパティを安全に確認する方法を、hasOwnPropertyとObject.hasOwnの違いから整理します。",{},"\u002Farticles\u002F2024\u002Fhow-to-use-javascript-built-in-objects","2024-11-24",{"title":7110,"description":7526},"articles\u002F2024\u002Fhow-to-use-javascript-built-in-objects",[4482],"\u002Fimages\u002Farticles\u002Fhow-to-use-javascript-built-in-objects.png","nujvvO9Kj5xXhtbuHUxO1l6JeNtgWjuj3S4rljZKkdU",{"id":7536,"title":7537,"body":7538,"description":7917,"extension":517,"meta":7918,"navigation":261,"path":7919,"publishDate":7920,"published":261,"seo":7921,"stem":7922,"tags":7923,"thumbnail":7924,"updated":7920,"__hash__":7925},"articles\u002Farticles\u002F2024\u002Fdescribe-javascript-deepcopy.md","JavaScriptのディープコピーとは？",{"type":7,"value":7539,"toc":7910},[7540,7542,7545,7548,7552,7555,7558,7567,7570,7577,7628,7641,7656,7659,7683,7686,7695,7699,7706,7752,7757,7772,7775,7799,7814,7821,7830,7834,7837,7846,7849,7874,7880,7882,7905,7908],[10,7541,12],{},[10,7543,7544],{},"今回は、JavaScriptにおけるオブジェクトのディープコピーについて紹介します。",[10,7546,7547],{},"シャローコピーとの違いや実装方法を理解しておくと、コピー先の変更が意図せずコピー元へ影響する問題を避けられます。",[28,7549,7551],{"id":7550},"ディープコピーとは","ディープコピーとは？",[10,7553,7554],{},"ディープコピーとは、コピー元とコピー先が、内部にあるオブジェクトの参照を共有しないコピーのことです。",[10,7556,7557],{},"たとえば、入れ子になったオブジェクトをコピーしたあと、コピー先の内側にある値を変更しても、コピー元の値には影響しません。",[10,7559,7560,7561,7566],{},"詳しい定義は、",[151,7562,7565],{"href":7563,"rel":7564},"https:\u002F\u002Fdeveloper.mozilla.org\u002Fja\u002Fdocs\u002FGlossary\u002FDeep_copy",[155],"MDNのディープコピー","も参照してください。",[28,7568,7569],{"id":7569},"シャローコピーでは参照が共有される",[10,7571,7572,7573,7576],{},"まずは、",[172,7574,7575],{},"Object.assign()"," を使ったシャローコピーを確認します。",[164,7578,7580],{"className":3797,"code":7579,"language":3799,"meta":170,"style":170},"const original = {\n  user: {\n    name: 'Yuri',\n  },\n  settings: {\n    theme: 'light',\n  },\n}\n\nconst shallowCopy = Object.assign({}, original)\n",[172,7581,7582,7587,7592,7597,7601,7606,7611,7615,7619,7623],{"__ignoreMap":170},[249,7583,7584],{"class":251,"line":252},[249,7585,7586],{},"const original = {\n",[249,7588,7589],{"class":251,"line":258},[249,7590,7591],{},"  user: {\n",[249,7593,7594],{"class":251,"line":265},[249,7595,7596],{},"    name: 'Yuri',\n",[249,7598,7599],{"class":251,"line":271},[249,7600,3877],{},[249,7602,7603],{"class":251,"line":277},[249,7604,7605],{},"  settings: {\n",[249,7607,7608],{"class":251,"line":283},[249,7609,7610],{},"    theme: 'light',\n",[249,7612,7613],{"class":251,"line":288},[249,7614,3877],{},[249,7616,7617],{"class":251,"line":294},[249,7618,1124],{},[249,7620,7621],{"class":251,"line":300},[249,7622,262],{"emptyLinePlaceholder":261},[249,7624,7625],{"class":251,"line":306},[249,7626,7627],{},"const shallowCopy = Object.assign({}, original)\n",[10,7629,7630,7633,7634,2126,7637,7640],{},[172,7631,7632],{},"Object.assign({}, original)"," で新しい外側のオブジェクトは作られますが、",[172,7635,7636],{},"user",[172,7638,7639],{},"settings"," はコピー元と同じオブジェクトを参照しています。",[164,7642,7644],{"className":3797,"code":7643,"language":3799,"meta":170,"style":170},"console.log(original === shallowCopy) \u002F\u002F false\nconsole.log(original.user === shallowCopy.user) \u002F\u002F true\n",[172,7645,7646,7651],{"__ignoreMap":170},[249,7647,7648],{"class":251,"line":252},[249,7649,7650],{},"console.log(original === shallowCopy) \u002F\u002F false\n",[249,7652,7653],{"class":251,"line":258},[249,7654,7655],{},"console.log(original.user === shallowCopy.user) \u002F\u002F true\n",[10,7657,7658],{},"そのため、コピー先にある入れ子の値を変更すると、コピー元にも影響します。",[164,7660,7662],{"className":3797,"code":7661,"language":3799,"meta":170,"style":170},"shallowCopy.user.name = 'Kohei'\n\nconsole.log(original.user.name) \u002F\u002F 「Kohei」\nconsole.log(shallowCopy.user.name) \u002F\u002F 「Kohei」\n",[172,7663,7664,7669,7673,7678],{"__ignoreMap":170},[249,7665,7666],{"class":251,"line":252},[249,7667,7668],{},"shallowCopy.user.name = 'Kohei'\n",[249,7670,7671],{"class":251,"line":258},[249,7672,262],{"emptyLinePlaceholder":261},[249,7674,7675],{"class":251,"line":265},[249,7676,7677],{},"console.log(original.user.name) \u002F\u002F 「Kohei」\n",[249,7679,7680],{"class":251,"line":271},[249,7681,7682],{},"console.log(shallowCopy.user.name) \u002F\u002F 「Kohei」\n",[10,7684,7685],{},"オブジェクトスプレッド構文も、同様にシャローコピーです。",[164,7687,7689],{"className":3797,"code":7688,"language":3799,"meta":170,"style":170},"const shallowCopy = { ...original }\n",[172,7690,7691],{"__ignoreMap":170},[249,7692,7693],{"class":251,"line":252},[249,7694,7688],{},[28,7696,7698],{"id":7697},"structuredcloneでディープコピーする","structuredCloneでディープコピーする",[10,7700,7701,7702,7705],{},"ディープコピーには、",[172,7703,7704],{},"structuredClone()"," を利用できます。",[164,7707,7709],{"className":3797,"code":7708,"language":3799,"meta":170,"style":170},"const original = {\n  user: {\n    name: 'Yuri',\n  },\n  settings: {\n    theme: 'light',\n  },\n}\n\nconst deepCopy = structuredClone(original)\n",[172,7710,7711,7715,7719,7723,7727,7731,7735,7739,7743,7747],{"__ignoreMap":170},[249,7712,7713],{"class":251,"line":252},[249,7714,7586],{},[249,7716,7717],{"class":251,"line":258},[249,7718,7591],{},[249,7720,7721],{"class":251,"line":265},[249,7722,7596],{},[249,7724,7725],{"class":251,"line":271},[249,7726,3877],{},[249,7728,7729],{"class":251,"line":277},[249,7730,7605],{},[249,7732,7733],{"class":251,"line":283},[249,7734,7610],{},[249,7736,7737],{"class":251,"line":288},[249,7738,3877],{},[249,7740,7741],{"class":251,"line":294},[249,7742,1124],{},[249,7744,7745],{"class":251,"line":300},[249,7746,262],{"emptyLinePlaceholder":261},[249,7748,7749],{"class":251,"line":306},[249,7750,7751],{},"const deepCopy = structuredClone(original)\n",[10,7753,7754,7756],{},[172,7755,7704],{}," で作ったコピーは、入れ子のオブジェクトもコピー元とは異なる参照になります。",[164,7758,7760],{"className":3797,"code":7759,"language":3799,"meta":170,"style":170},"console.log(original === deepCopy) \u002F\u002F false\nconsole.log(original.user === deepCopy.user) \u002F\u002F false\n",[172,7761,7762,7767],{"__ignoreMap":170},[249,7763,7764],{"class":251,"line":252},[249,7765,7766],{},"console.log(original === deepCopy) \u002F\u002F false\n",[249,7768,7769],{"class":251,"line":258},[249,7770,7771],{},"console.log(original.user === deepCopy.user) \u002F\u002F false\n",[10,7773,7774],{},"コピー先を変更しても、コピー元には影響しません。",[164,7776,7778],{"className":3797,"code":7777,"language":3799,"meta":170,"style":170},"deepCopy.user.name = 'Kohei'\n\nconsole.log(original.user.name) \u002F\u002F 「Yuri」\nconsole.log(deepCopy.user.name) \u002F\u002F 「Kohei」\n",[172,7779,7780,7785,7789,7794],{"__ignoreMap":170},[249,7781,7782],{"class":251,"line":252},[249,7783,7784],{},"deepCopy.user.name = 'Kohei'\n",[249,7786,7787],{"class":251,"line":258},[249,7788,262],{"emptyLinePlaceholder":261},[249,7790,7791],{"class":251,"line":265},[249,7792,7793],{},"console.log(original.user.name) \u002F\u002F 「Yuri」\n",[249,7795,7796],{"class":251,"line":271},[249,7797,7798],{},"console.log(deepCopy.user.name) \u002F\u002F 「Kohei」\n",[10,7800,7801,7803,7804,2561,7807,2561,7810,7813],{},[172,7802,7704],{}," は通常のオブジェクトや配列だけでなく、",[172,7805,7806],{},"Date",[172,7808,7809],{},"Map",[172,7811,7812],{},"Set"," など、構造化複製アルゴリズムが対応している型をコピーできます。また、循環参照を持つオブジェクトにも対応しています。",[10,7815,7816,7817,7820],{},"ただし、関数など構造化複製できない値が含まれている場合は ",[172,7818,7819],{},"DataCloneError"," が発生します。すべてのJavaScriptの値を無条件にコピーできるわけではありません。",[10,7822,7823,7824,7829],{},"詳しい対応範囲は、",[151,7825,7828],{"href":7826,"rel":7827},"https:\u002F\u002Fdeveloper.mozilla.org\u002Fja\u002Fdocs\u002FWeb\u002FAPI\u002FWindow\u002FstructuredClone",[155],"MDNのstructuredClone()","を確認してください。",[28,7831,7833],{"id":7832},"jsonを使ったディープコピーの注意点","JSONを使ったディープコピーの注意点",[10,7835,7836],{},"単純なデータだけを扱う場合、JSONへ変換して戻す方法もあります。",[164,7838,7840],{"className":3797,"code":7839,"language":3799,"meta":170,"style":170},"const deepCopy = JSON.parse(JSON.stringify(original))\n",[172,7841,7842],{"__ignoreMap":170},[249,7843,7844],{"class":251,"line":252},[249,7845,7839],{},[10,7847,7848],{},"ただし、この方法はJSONとして表現できる値に限られます。",[470,7850,7851,7856,7865,7871],{},[473,7852,7853,7855],{},[172,7854,7806],{}," は文字列へ変換される",[473,7857,7858,7860,7861,7864],{},[172,7859,4047],{},"、関数、",[172,7862,7863],{},"Symbol"," などは正しく保持できない",[473,7866,7867,7870],{},[172,7868,7869],{},"BigInt"," を含むと例外が発生する",[473,7872,7873],{},"循環参照を持つオブジェクトは変換できない",[10,7875,7876,7877,7879],{},"対象がJSON互換のデータだと分かっている場合には使えますが、一般的なディープコピーとしては ",[172,7878,7704],{}," の方が意図を表しやすく、扱える型も多くなります。",[28,7881,465],{"id":465},[470,7883,7884,7889,7892,7897,7902],{},[473,7885,7886,7888],{},[172,7887,7575],{}," とオブジェクトスプレッド構文はシャローコピーになる",[473,7890,7891],{},"シャローコピーでは、入れ子のオブジェクトの参照がコピー元と共有される",[473,7893,7894,7896],{},[172,7895,7704],{}," を使うと、対応している値をディープコピーできる",[473,7898,7899,7901],{},[172,7900,7704],{}," でも、関数などコピーできない値がある",[473,7903,7904],{},"JSONによるコピーは、JSON互換データだけに限定して使う",[10,7906,7907],{},"コピー方法を選ぶときは、対象のデータ構造と、コピー後にどの階層まで独立して変更したいかを確認することが大切です。",[499,7909,501],{},{"title":170,"searchDepth":258,"depth":258,"links":7911},[7912,7913,7914,7915,7916],{"id":7550,"depth":258,"text":7551},{"id":7569,"depth":258,"text":7569},{"id":7697,"depth":258,"text":7698},{"id":7832,"depth":258,"text":7833},{"id":465,"depth":258,"text":465},"JavaScriptのシャローコピーとディープコピーの違いを確認し、structuredCloneを使った実装方法と注意点を整理します。",{},"\u002Farticles\u002F2024\u002Fdescribe-javascript-deepcopy","2024-11-23",{"title":7537,"description":7917},"articles\u002F2024\u002Fdescribe-javascript-deepcopy",[4482],"\u002Fimages\u002Farticles\u002Fdescribe-javascript-deepcopy.png","dtSQ5LrS1Kfo1hFYE2MzMKOvrhU_5JGE1X1eQ9eHhIY",{"id":7927,"title":7928,"body":7929,"description":8340,"extension":517,"meta":8341,"navigation":261,"path":8342,"publishDate":8343,"published":261,"seo":8344,"stem":8345,"tags":8346,"thumbnail":8347,"updated":8348,"__hash__":8349},"articles\u002Farticles\u002F2024\u002Fdescribe-behavior-javascript-this.md","JavaScriptのthisの挙動について呼び出し元で整理する",{"type":7,"value":7930,"toc":8332},[7931,7933,7939,7943,7948,7954,7957,7960,7966,7974,7976,7982,7988,7997,8000,8040,8047,8066,8068,8074,8094,8097,8134,8146,8166,8172,8175,8178,8220,8238,8247,8261,8271,8286,8288,8293,8325,8330],[10,7932,12],{},[10,7934,7935,7936,7938],{},"今回は、プロジェクトや個人開発で振り回されることが多かったJavaScriptの ",[172,7937,7459],{}," の挙動について、あらためて振り返ります。自分をはじめ、初学者の方も知っておくと開発が楽になるかと思います。",[28,7940,7942],{"id":7941},"そもそもthisってなんだ","そもそも「this」ってなんだ？",[10,7944,7945,7947],{},[172,7946,7459],{}," は、関数が実行されたときのコンテキストを参照するためのキーワードです。",[10,7949,7950,7951,7953],{},"同じ関数であっても、どのように呼び出されたかによって ",[172,7952,7459],{}," が参照する値は変わります。この特徴が便利なところでもあり、難しいところでもあります。",[10,7955,7956],{},"それでは、呼び出し方によって参照先がどう変わるのか見てみましょう。",[28,7958,7959],{"id":7959},"使用する場所ごとのthis",[10,7961,7962,7963,7965],{},"この記事では、",[172,7964,7459],{}," を使用するケースを次の2つに分けて確認します。",[470,7967,7968,7971],{},[473,7969,7970],{},"オブジェクトのメソッドとして呼び出す場合",[473,7972,7973],{},"通常の関数として呼び出す場合",[28,7975,7970],{"id":7970},[10,7977,7978,7979,7981],{},"オブジェクトのメソッドとして呼び出した場合、",[172,7980,7459],{}," は基本的に呼び出し元のオブジェクトを参照します。",[10,7983,7984,7985,7987],{},"ここでいう呼び出し元のオブジェクトとは、次の例では ",[172,7986,7195],{}," のことです。",[164,7989,7991],{"className":3797,"code":7990,"language":3799,"meta":170,"style":170},"const obj = {}\n",[172,7992,7993],{"__ignoreMap":170},[249,7994,7995],{"class":251,"line":252},[249,7996,7990],{},[10,7998,7999],{},"実際に挙動を見てみましょう。",[164,8001,8003],{"className":3797,"code":8002,"language":3799,"meta":170,"style":170},"const obj = {\n  name: 'Yuri',\n  message: function () {\n    console.log('Hello ' + this.name)\n  },\n}\n\nobj.message()\n",[172,8004,8005,8009,8013,8018,8023,8027,8031,8035],{"__ignoreMap":170},[249,8006,8007],{"class":251,"line":252},[249,8008,7172],{},[249,8010,8011],{"class":251,"line":258},[249,8012,3998],{},[249,8014,8015],{"class":251,"line":265},[249,8016,8017],{},"  message: function () {\n",[249,8019,8020],{"class":251,"line":271},[249,8021,8022],{},"    console.log('Hello ' + this.name)\n",[249,8024,8025],{"class":251,"line":277},[249,8026,3877],{},[249,8028,8029],{"class":251,"line":283},[249,8030,1124],{},[249,8032,8033],{"class":251,"line":288},[249,8034,262],{"emptyLinePlaceholder":261},[249,8036,8037],{"class":251,"line":294},[249,8038,8039],{},"obj.message()\n",[10,8041,8042,8043,8046],{},"この例では、",[172,8044,8045],{},"Hello Yuri"," と出力されます。",[10,8048,8049,8052,8053,8055,8056,8058,8059,8055,8062,8065],{},[172,8050,8051],{},"obj.message()"," という形で呼び出しているため、メソッド内の ",[172,8054,7459],{}," は ",[172,8057,7195],{}," を参照します。したがって、",[172,8060,8061],{},"this.name",[172,8063,8064],{},"obj.name"," として評価されます。",[28,8067,7973],{"id":7973},[10,8069,8070,8071,8073],{},"通常の関数として呼び出した場合、",[172,8072,7459],{}," の値は実行モードによって異なります。",[470,8075,8076,8086],{},[473,8077,8078,8079,8081,8082,8085],{},"非厳格モードのブラウザでは、",[172,8080,7459],{}," はグローバルオブジェクトの ",[172,8083,8084],{},"window"," を参照する",[473,8087,8088,8089,8055,8091,8093],{},"厳格モードやES Modulesでは、",[172,8090,7459],{},[172,8092,4047],{}," になる",[10,8095,8096],{},"次のコードは、ブラウザの非厳格モードで実行する例です。",[164,8098,8100],{"className":3797,"code":8099,"language":3799,"meta":170,"style":170},"window.name = 'Yuri'\n\nfunction message() {\n  console.log('Hello ' + this.name)\n}\n\nmessage()\n",[172,8101,8102,8107,8111,8116,8121,8125,8129],{"__ignoreMap":170},[249,8103,8104],{"class":251,"line":252},[249,8105,8106],{},"window.name = 'Yuri'\n",[249,8108,8109],{"class":251,"line":258},[249,8110,262],{"emptyLinePlaceholder":261},[249,8112,8113],{"class":251,"line":265},[249,8114,8115],{},"function message() {\n",[249,8117,8118],{"class":251,"line":271},[249,8119,8120],{},"  console.log('Hello ' + this.name)\n",[249,8122,8123],{"class":251,"line":277},[249,8124,1124],{},[249,8126,8127],{"class":251,"line":283},[249,8128,262],{"emptyLinePlaceholder":261},[249,8130,8131],{"class":251,"line":288},[249,8132,8133],{},"message()\n",[10,8135,8136,8137,8139,8140,8143,8144,8046],{},"非厳格モードでは ",[172,8138,8061],{}," が ",[172,8141,8142],{},"window.name"," として評価されるため、",[172,8145,8045],{},[1901,8147,8148],{},[10,8149,8150,2126,8153,8155,8156,8158,8159,8162,8163,8165],{},[172,8151,8152],{},"let",[172,8154,4738],{}," で宣言した変数は、",[172,8157,8084],{}," オブジェクトのプロパティとして追加されません。一方、ブラウザでトップレベルに ",[172,8160,8161],{},"var"," を使って宣言した変数は、",[172,8164,8084],{}," のプロパティになります。",[10,8167,8168,8169,8171],{},"現在のフロントエンド開発ではES Modulesが広く使われています。ES Modulesは自動的に厳格モードとして扱われるため、通常の関数呼び出しで ",[172,8170,7459],{}," に依存する実装は避けた方が安全です。",[28,8173,8174],{"id":8174},"オブジェクトのメソッドを変数へ代入した場合",[10,8176,8177],{},"ここまでを踏まえて、オブジェクトのメソッドを変数へ代入した場合の挙動を見てみましょう。",[164,8179,8181],{"className":3797,"code":8180,"language":3799,"meta":170,"style":170},"const obj = {\n  name: 'Yuri',\n  message: function () {\n    console.log('Hello ' + this.name)\n  },\n}\n\nconst message = obj.message\nmessage()\n",[172,8182,8183,8187,8191,8195,8199,8203,8207,8211,8216],{"__ignoreMap":170},[249,8184,8185],{"class":251,"line":252},[249,8186,7172],{},[249,8188,8189],{"class":251,"line":258},[249,8190,3998],{},[249,8192,8193],{"class":251,"line":265},[249,8194,8017],{},[249,8196,8197],{"class":251,"line":271},[249,8198,8022],{},[249,8200,8201],{"class":251,"line":277},[249,8202,3877],{},[249,8204,8205],{"class":251,"line":283},[249,8206,1124],{},[249,8208,8209],{"class":251,"line":288},[249,8210,262],{"emptyLinePlaceholder":261},[249,8212,8213],{"class":251,"line":294},[249,8214,8215],{},"const message = obj.message\n",[249,8217,8218],{"class":251,"line":300},[249,8219,8133],{},[10,8221,8222,8225,8226,8228,8229,8232,8233,2557,8235,8237],{},[172,8223,8224],{},"const message = obj.message"," では、関数そのものを変数へ代入しています。その後は ",[172,8227,8051],{}," ではなく ",[172,8230,8231],{},"message()"," として呼び出しているため、",[172,8234,7459],{},[172,8236,7195],{}," の結び付きは失われます。",[10,8239,8136,8240,8139,8242,2576,8244,8246],{},[172,8241,7459],{},[172,8243,8084],{},[172,8245,8142],{}," が設定されていなければ、実行環境に応じて空文字などが返ります。",[10,8248,8249,8250,8139,8252,8254,8255,8257,8258,8260],{},"厳格モードやES Modulesでは ",[172,8251,7459],{},[172,8253,4047],{}," になるため、",[172,8256,8061],{}," を読み取ろうとすると ",[172,8259,4227],{}," が発生します。",[10,8262,8263,8264,8267,8268,8270],{},"このような場合は、",[172,8265,8266],{},"bind()"," を使って ",[172,8269,7459],{}," の参照先を固定できます。",[164,8272,8274],{"className":3797,"code":8273,"language":3799,"meta":170,"style":170},"const message = obj.message.bind(obj)\nmessage() \u002F\u002F 「Hello Yuri」と出力される\n",[172,8275,8276,8281],{"__ignoreMap":170},[249,8277,8278],{"class":251,"line":252},[249,8279,8280],{},"const message = obj.message.bind(obj)\n",[249,8282,8283],{"class":251,"line":258},[249,8284,8285],{},"message() \u002F\u002F 「Hello Yuri」と出力される\n",[28,8287,465],{"id":465},[10,8289,8290,8292],{},[172,8291,7459],{}," の参照先は、関数を定義した場所だけではなく、主に関数の呼び出し方によって決まります。",[470,8294,8295,8304,8314,8317],{},[473,8296,8297,8299,8300,8055,8302,8085],{},[172,8298,8051],{}," のようなメソッド呼び出しでは、",[172,8301,7459],{},[172,8303,7195],{},[473,8305,8306,8308,8309,8311,8312,8093],{},[172,8307,8231],{}," のような通常の関数呼び出しでは、非厳格モードのブラウザなら ",[172,8310,8084],{},"、厳格モードやES Modulesなら ",[172,8313,4047],{},[473,8315,8316],{},"メソッドを変数へ代入すると、元のオブジェクトとの結び付きは失われる",[473,8318,8319,8320,3713,8322,8324],{},"元のオブジェクトを参照させたい場合は、",[172,8321,8266],{},[172,8323,7459],{}," を固定できる",[10,8326,8327,8329],{},[172,8328,7459],{}," で迷ったときは「この関数はどのような形で呼び出されているか」を確認すると、参照先を判断しやすくなります。",[499,8331,501],{},{"title":170,"searchDepth":258,"depth":258,"links":8333},[8334,8335,8336,8337,8338,8339],{"id":7941,"depth":258,"text":7942},{"id":7959,"depth":258,"text":7959},{"id":7970,"depth":258,"text":7970},{"id":7973,"depth":258,"text":7973},{"id":8174,"depth":258,"text":8174},{"id":465,"depth":258,"text":465},"JavaScriptのthisが何を参照するのか、メソッド呼び出しと関数呼び出しの違いから整理します。",{},"\u002Farticles\u002F2024\u002Fdescribe-behavior-javascript-this","2024-11-20",{"title":7928,"description":8340},"articles\u002F2024\u002Fdescribe-behavior-javascript-this",[4482],"\u002Fimages\u002Farticles\u002Fdescribe-behavior-javascript-this.png","2025-03-21","Kay_1TeIK8YsouKEwYLRPzbQMnabHxZ_GWvHciKSZBs",[8351,8840,9193,9875,10399,10863,11408,12755,13133,13504,13830,14129],{"id":530,"title":531,"body":8352,"description":1226,"extension":517,"meta":8837,"navigation":261,"path":1228,"publishDate":1229,"published":261,"seo":8838,"stem":1231,"tags":8839,"thumbnail":1236,"updated":526,"__hash__":1237},{"type":7,"value":8353,"toc":8822},[8354,8356,8358,8360,8362,8366,8368,8370,8372,8408,8410,8412,8414,8416,8418,8420,8424,8426,8442,8444,8449,8451,8453,8455,8459,8461,8463,8465,8467,8469,8471,8473,8487,8491,8493,8495,8497,8499,8501,8503,8507,8509,8511,8513,8549,8551,8553,8555,8621,8623,8633,8637,8639,8641,8643,8645,8647,8661,8665,8667,8669,8685,8687,8689,8691,8693,8695,8705,8707,8712,8716,8722,8766,8770,8772,8780,8782,8786,8802,8804,8806,8808,8810,8812,8814,8816,8818,8820],[10,8355,12],{},[10,8357,538],{},[10,8359,541],{},[10,8361,544],{},[10,8363,547,8364,551],{},[17,8365,550],{},[10,8367,554],{},[28,8369,558],{"id":557},[10,8371,561],{},[38,8373,8374,8382],{},[41,8375,8376],{},[44,8377,8378,8380],{},[47,8379,570],{},[47,8381,573],{},[57,8383,8384,8390,8396,8402],{},[44,8385,8386,8388],{},[62,8387,580],{},[62,8389,583],{},[44,8391,8392,8394],{},[62,8393,588],{},[62,8395,591],{},[44,8397,8398,8400],{},[62,8399,596],{},[62,8401,599],{},[44,8403,8404,8406],{},[62,8405,604],{},[62,8407,607],{},[10,8409,610],{},[10,8411,613],{},[10,8413,616],{},[10,8415,619],{},[28,8417,623],{"id":622},[10,8419,626],{},[10,8421,629,8422,633],{},[17,8423,632],{},[10,8425,636],{},[638,8427,8428,8430,8432,8434,8436,8438,8440],{},[473,8429,642],{},[473,8431,645],{},[473,8433,648],{},[473,8435,651],{},[473,8437,654],{},[473,8439,657],{},[473,8441,660],{},[10,8443,663],{},[164,8445,8447],{"className":8446,"code":667,"language":169,"meta":170},[167],[172,8448,667],{"__ignoreMap":170},[10,8450,672],{},[10,8452,675],{},[404,8454,678],{"id":678},[10,8456,681,8457,686],{},[151,8458,685],{"href":684},[10,8460,689],{},[10,8462,692],{},[10,8464,695],{},[28,8466,699],{"id":698},[10,8468,702],{},[10,8470,705],{},[10,8472,708],{},[470,8474,8475,8477,8479,8481,8483,8485],{},[473,8476,713],{},[473,8478,716],{},[473,8480,719],{},[473,8482,722],{},[473,8484,725],{},[473,8486,728],{},[10,8488,731,8489,735],{},[172,8490,734],{},[10,8492,738],{},[10,8494,741],{},[28,8496,745],{"id":744},[10,8498,748],{},[10,8500,751],{},[10,8502,754],{},[10,8504,757,8505,761],{},[17,8506,760],{},[10,8508,764],{},[28,8510,767],{"id":767},[10,8512,770],{},[38,8514,8515,8523],{},[41,8516,8517],{},[44,8518,8519,8521],{},[47,8520,779],{},[47,8522,782],{},[57,8524,8525,8531,8537,8543],{},[44,8526,8527,8529],{},[62,8528,789],{},[62,8530,792],{},[44,8532,8533,8535],{},[62,8534,797],{},[62,8536,800],{},[44,8538,8539,8541],{},[62,8540,805],{},[62,8542,808],{},[44,8544,8545,8547],{},[62,8546,813],{},[62,8548,816],{},[10,8550,819],{},[10,8552,822],{},[10,8554,825],{},[38,8556,8557,8565],{},[41,8558,8559],{},[44,8560,8561,8563],{},[47,8562,834],{},[47,8564,837],{},[57,8566,8567,8573,8579,8585,8591,8597,8603,8609,8615],{},[44,8568,8569,8571],{},[62,8570,844],{},[62,8572,847],{},[44,8574,8575,8577],{},[62,8576,852],{},[62,8578,855],{},[44,8580,8581,8583],{},[62,8582,860],{},[62,8584,863],{},[44,8586,8587,8589],{},[62,8588,868],{},[62,8590,871],{},[44,8592,8593,8595],{},[62,8594,876],{},[62,8596,879],{},[44,8598,8599,8601],{},[62,8600,884],{},[62,8602,887],{},[44,8604,8605,8607],{},[62,8606,892],{},[62,8608,895],{},[44,8610,8611,8613],{},[62,8612,900],{},[62,8614,903],{},[44,8616,8617,8619],{},[62,8618,908],{},[62,8620,911],{},[10,8622,914],{},[164,8624,8625],{"className":917,"code":918,"language":797,"meta":170,"style":170},[172,8626,8627],{"__ignoreMap":170},[249,8628,8629,8631],{"class":251,"line":252},[249,8630,926],{"class":925},[249,8632,930],{"class":929},[10,8634,933,8635,937],{},[172,8636,936],{},[10,8638,940],{},[28,8640,944],{"id":943},[10,8642,947],{},[10,8644,950],{},[10,8646,953],{},[164,8648,8649],{"className":917,"code":956,"language":797,"meta":170,"style":170},[172,8650,8651],{"__ignoreMap":170},[249,8652,8653,8655,8657,8659],{"class":251,"line":252},[249,8654,963],{"class":925},[249,8656,966],{"class":929},[249,8658,969],{"class":929},[249,8660,972],{"class":929},[10,8662,975,8663,979],{},[17,8664,978],{},[404,8666,982],{"id":982},[10,8668,985],{},[164,8670,8671],{"className":917,"code":988,"language":797,"meta":170,"style":170},[172,8672,8673],{"__ignoreMap":170},[249,8674,8675,8677,8679,8681,8683],{"class":251,"line":252},[249,8676,996],{"class":995},[249,8678,999],{"class":929},[249,8680,1003],{"class":1002},[249,8682,1006],{"class":929},[249,8684,1009],{"class":1002},[10,8686,1012],{},[10,8688,1015],{},[10,8690,1018],{},[404,8692,1022],{"id":1021},[10,8694,1025],{},[164,8696,8697],{"className":917,"code":1028,"language":797,"meta":170,"style":170},[172,8698,8699],{"__ignoreMap":170},[249,8700,8701,8703],{"class":251,"line":252},[249,8702,1035],{"class":925},[249,8704,1038],{"class":929},[10,8706,1041],{},[164,8708,8710],{"className":8709,"code":1045,"language":169,"meta":170},[167],[172,8711,1045],{"__ignoreMap":170},[10,8713,1050,8714,1054],{},[172,8715,1053],{},[10,8717,1057,8718,1061,8720,1065],{},[172,8719,1060],{},[172,8721,1064],{},[164,8723,8724],{"className":1068,"code":1069,"language":1070,"meta":170,"style":170},[172,8725,8726,8730,8742,8758,8762],{"__ignoreMap":170},[249,8727,8728],{"class":251,"line":252},[249,8729,1077],{"class":1002},[249,8731,8732,8734,8736,8738,8740],{"class":251,"line":258},[249,8733,1082],{"class":1002},[249,8735,1064],{"class":1085},[249,8737,1088],{"class":1002},[249,8739,1091],{"class":1002},[249,8741,1094],{"class":1002},[249,8743,8744,8746,8748,8750,8752,8754,8756],{"class":251,"line":265},[249,8745,1099],{"class":1002},[249,8747,1102],{"class":925},[249,8749,1088],{"class":1002},[249,8751,1091],{"class":1002},[249,8753,1109],{"class":1002},[249,8755,813],{"class":929},[249,8757,1114],{"class":1002},[249,8759,8760],{"class":251,"line":271},[249,8761,1119],{"class":1002},[249,8763,8764],{"class":251,"line":277},[249,8765,1124],{"class":1002},[10,8767,1127,8768,1131],{},[172,8769,1130],{},[10,8771,1134],{},[10,8773,1137,8774,1141,8776,1145,8778,1148],{},[172,8775,1140],{},[172,8777,1144],{},[172,8779,1035],{},[404,8781,1151],{"id":1151},[10,8783,1154,8784,1157],{},[172,8785,936],{},[164,8787,8788],{"className":917,"code":1160,"language":797,"meta":170,"style":170},[172,8789,8790],{"__ignoreMap":170},[249,8791,8792,8794,8796,8798,8800],{"class":251,"line":252},[249,8793,1167],{"class":1085},[249,8795,1170],{"class":929},[249,8797,1174],{"class":1173},[249,8799,1177],{"class":1002},[249,8801,1180],{"class":1173},[10,8803,1183],{},[10,8805,1186],{},[28,8807,1189],{"id":1189},[10,8809,1192],{},[10,8811,1195],{},[10,8813,1198],{},[10,8815,1201],{},[10,8817,1204],{},[10,8819,1207],{},[499,8821,1210],{},{"title":170,"searchDepth":258,"depth":258,"links":8823},[8824,8825,8828,8829,8830,8831,8836],{"id":557,"depth":258,"text":558},{"id":622,"depth":258,"text":623,"children":8826},[8827],{"id":678,"depth":265,"text":678},{"id":698,"depth":258,"text":699},{"id":744,"depth":258,"text":745},{"id":767,"depth":258,"text":767},{"id":943,"depth":258,"text":944,"children":8832},[8833,8834,8835],{"id":982,"depth":265,"text":982},{"id":1021,"depth":265,"text":1022},{"id":1151,"depth":265,"text":1151},{"id":1189,"depth":258,"text":1189},{},{"title":531,"description":1226},[1233,1234,588,1235],{"id":4,"title":5,"body":8841,"description":516,"extension":517,"meta":9190,"navigation":261,"path":519,"publishDate":520,"published":261,"seo":9191,"stem":522,"tags":9192,"thumbnail":525,"updated":526,"__hash__":527},{"type":7,"value":8842,"toc":9176},[8843,8845,8849,8851,8853,8855,8857,8859,8889,8891,8937,8941,8943,8948,8950,8952,8957,8959,8961,8963,8968,8972,8974,8976,8981,8983,8985,8990,8992,8997,8999,9001,9003,9005,9069,9073,9078,9080,9084,9086,9088,9090,9095,9099,9101,9106,9108,9110,9112,9114,9116,9118,9123,9125,9127,9131,9136,9138,9140,9142,9144,9146,9148,9150,9152,9154,9156,9168,9172,9174],[10,8844,12],{},[10,8846,15,8847,20],{},[17,8848,19],{},[10,8850,23],{},[10,8852,26],{},[28,8854,30],{"id":30},[10,8856,33],{},[10,8858,36],{},[38,8860,8861,8871],{},[41,8862,8863],{},[44,8864,8865,8867,8869],{},[47,8866,49],{},[47,8868,52],{},[47,8870,55],{},[57,8872,8873,8881],{},[44,8874,8875,8877,8879],{},[62,8876,64],{},[62,8878,67],{},[62,8880,70],{},[44,8882,8883,8885,8887],{},[62,8884,75],{},[62,8886,70],{},[62,8888,67],{},[10,8890,82],{},[38,8892,8893,8903],{},[41,8894,8895],{},[44,8896,8897,8899,8901],{},[47,8898,91],{},[47,8900,64],{},[47,8902,75],{},[57,8904,8905,8913,8921,8929],{},[44,8906,8907,8909,8911],{},[62,8908,102],{},[62,8910,105],{},[62,8912],{},[44,8914,8915,8917,8919],{},[62,8916,112],{},[62,8918],{},[62,8920,117],{},[44,8922,8923,8925,8927],{},[62,8924,122],{},[62,8926,125],{},[62,8928],{},[44,8930,8931,8933,8935],{},[62,8932,132],{},[62,8934],{},[62,8936,137],{},[10,8938,140,8939,144],{},[17,8940,143],{},[10,8942,147],{},[10,8944,8945],{},[151,8946,156],{"href":153,"rel":8947},[155],[28,8949,159],{"id":159},[10,8951,162],{},[164,8953,8955],{"className":8954,"code":168,"language":169,"meta":170},[167],[172,8956,168],{"__ignoreMap":170},[10,8958,176],{},[10,8960,179],{},[10,8962,182],{},[10,8964,8965],{},[151,8966,156],{"href":153,"rel":8967},[155],[10,8969,190,8970,144],{},[17,8971,193],{},[28,8973,197],{"id":196},[10,8975,200],{},[164,8977,8979],{"className":8978,"code":204,"language":169,"meta":170},[167],[172,8980,204],{"__ignoreMap":170},[10,8982,209],{},[10,8984,212],{},[164,8986,8988],{"className":8987,"code":216,"language":169,"meta":170},[167],[172,8989,216],{"__ignoreMap":170},[10,8991,221],{},[164,8993,8995],{"className":8994,"code":225,"language":169,"meta":170},[167],[172,8996,225],{"__ignoreMap":170},[10,8998,230],{},[10,9000,233],{},[28,9002,237],{"id":236},[10,9004,240],{},[164,9006,9007],{"className":243,"code":244,"language":245,"meta":170,"style":170},[172,9008,9009,9013,9017,9021,9025,9029,9033,9037,9041,9045,9049,9053,9057,9061,9065],{"__ignoreMap":170},[249,9010,9011],{"class":251,"line":252},[249,9012,255],{},[249,9014,9015],{"class":251,"line":258},[249,9016,262],{"emptyLinePlaceholder":261},[249,9018,9019],{"class":251,"line":265},[249,9020,268],{},[249,9022,9023],{"class":251,"line":271},[249,9024,274],{},[249,9026,9027],{"class":251,"line":277},[249,9028,280],{},[249,9030,9031],{"class":251,"line":283},[249,9032,262],{"emptyLinePlaceholder":261},[249,9034,9035],{"class":251,"line":288},[249,9036,291],{},[249,9038,9039],{"class":251,"line":294},[249,9040,297],{},[249,9042,9043],{"class":251,"line":300},[249,9044,303],{},[249,9046,9047],{"class":251,"line":306},[249,9048,262],{"emptyLinePlaceholder":261},[249,9050,9051],{"class":251,"line":311},[249,9052,314],{},[249,9054,9055],{"class":251,"line":317},[249,9056,320],{},[249,9058,9059],{"class":251,"line":323},[249,9060,326],{},[249,9062,9063],{"class":251,"line":329},[249,9064,262],{"emptyLinePlaceholder":261},[249,9066,9067],{"class":251,"line":334},[249,9068,337],{},[10,9070,340,9071,344],{},[172,9072,343],{},[10,9074,9075],{},[151,9076,351],{"href":349,"rel":9077},[155],[10,9079,354],{},[10,9081,357,9082,361],{},[172,9083,360],{},[10,9085,364],{},[28,9087,368],{"id":367},[10,9089,371],{},[164,9091,9093],{"className":9092,"code":375,"language":169,"meta":170},[167],[172,9094,375],{"__ignoreMap":170},[10,9096,380,9097,384],{},[172,9098,383],{},[10,9100,387],{},[164,9102,9104],{"className":9103,"code":391,"language":169,"meta":170},[167],[172,9105,391],{"__ignoreMap":170},[10,9107,396],{},[10,9109,399],{},[28,9111,402],{"id":402},[404,9113,406],{"id":406},[10,9115,409],{},[10,9117,412],{},[10,9119,9120],{},[151,9121,156],{"href":153,"rel":9122},[155],[404,9124,420],{"id":420},[10,9126,423],{},[10,9128,426,9129,430],{},[172,9130,429],{},[10,9132,9133],{},[151,9134,437],{"href":435,"rel":9135},[155],[10,9137,440],{},[404,9139,443],{"id":443},[10,9141,446],{},[10,9143,449],{},[404,9145,453],{"id":452},[10,9147,456],{},[10,9149,459],{},[10,9151,462],{},[28,9153,465],{"id":465},[10,9155,468],{},[470,9157,9158,9160,9162,9164,9166],{},[473,9159,475],{},[473,9161,478],{},[473,9163,481],{},[473,9165,484],{},[473,9167,487],{},[10,9169,490,9170,494],{},[17,9171,493],{},[10,9173,497],{},[499,9175,501],{},{"title":170,"searchDepth":258,"depth":258,"links":9177},[9178,9179,9180,9181,9182,9183,9189],{"id":30,"depth":258,"text":30},{"id":159,"depth":258,"text":159},{"id":196,"depth":258,"text":197},{"id":236,"depth":258,"text":237},{"id":367,"depth":258,"text":368},{"id":402,"depth":258,"text":402,"children":9184},[9185,9186,9187,9188],{"id":406,"depth":265,"text":406},{"id":420,"depth":265,"text":420},{"id":443,"depth":265,"text":443},{"id":452,"depth":265,"text":453},{"id":465,"depth":258,"text":465},{},{"title":5,"description":516},[524],{"id":1592,"title":685,"body":9194,"description":2475,"extension":517,"meta":9872,"navigation":261,"path":684,"publishDate":2477,"published":261,"seo":9873,"stem":2479,"tags":9874,"thumbnail":2483,"updated":2477,"__hash__":2484},{"type":7,"value":9195,"toc":9858},[9196,9198,9200,9202,9204,9206,9208,9210,9212,9214,9216,9218,9220,9224,9226,9234,9236,9238,9240,9244,9266,9268,9273,9275,9280,9284,9286,9290,9292,9344,9348,9368,9376,9380,9385,9389,9394,9402,9407,9409,9411,9415,9417,9419,9421,9445,9469,9473,9477,9482,9484,9536,9538,9566,9594,9596,9604,9606,9608,9613,9615,9633,9635,9655,9675,9677,9679,9681,9683,9685,9690,9692,9694,9696,9740,9744,9768,9770,9772,9774,9776,9778,9786,9788,9792,9794,9796,9834,9836,9838,9840,9842,9844,9846,9850,9852,9856],[10,9197,12],{},[10,9199,1599],{},[10,9201,1602],{},[10,9203,1605],{},[10,9205,1608],{},[10,9207,1611],{},[10,9209,1614],{},[10,9211,1617],{},[28,9213,1621],{"id":1620},[10,9215,1624],{},[10,9217,1627],{},[10,9219,1630],{},[10,9221,1633,9222,1637],{},[172,9223,1636],{},[10,9225,1640],{},[470,9227,9228,9230,9232],{},[473,9229,1645],{},[473,9231,1648],{},[473,9233,1651],{},[10,9235,1654],{},[28,9237,1658],{"id":1657},[10,9239,1661],{},[10,9241,1664,9242,1668],{},[172,9243,1667],{},[164,9245,9246],{"className":1671,"code":1672,"language":1673,"meta":170,"style":170},[172,9247,9248,9254],{"__ignoreMap":170},[249,9249,9250,9252],{"class":251,"line":252},[249,9251,1680],{"class":995},[249,9253,1683],{"class":929},[249,9255,9256,9258,9260,9262,9264],{"class":251,"line":258},[249,9257,1688],{"class":925},[249,9259,1691],{"class":929},[249,9261,1694],{"class":929},[249,9263,1697],{"class":929},[249,9265,1700],{"class":929},[10,9267,1703],{},[164,9269,9271],{"className":9270,"code":1707,"language":169,"meta":170},[167],[172,9272,1707],{"__ignoreMap":170},[10,9274,1712],{},[164,9276,9278],{"className":9277,"code":1716,"language":169,"meta":170},[167],[172,9279,1716],{"__ignoreMap":170},[10,9281,1721,9282,1725],{},[17,9283,1724],{},[28,9285,1729],{"id":1728},[10,9287,1732,9288,1736],{},[172,9289,1735],{},[10,9291,1739],{},[164,9293,9294],{"className":1742,"code":1743,"language":1744,"meta":170,"style":170},[172,9295,9296,9302,9308,9316,9322,9328,9334],{"__ignoreMap":170},[249,9297,9298,9300],{"class":251,"line":252},[249,9299,1752],{"class":1751},[249,9301,1755],{"class":1002},[249,9303,9304,9306],{"class":251,"line":258},[249,9305,1760],{"class":1751},[249,9307,1755],{"class":1002},[249,9309,9310,9312,9314],{"class":251,"line":265},[249,9311,1767],{"class":1751},[249,9313,1091],{"class":1002},[249,9315,1773],{"class":1772},[249,9317,9318,9320],{"class":251,"line":271},[249,9319,1778],{"class":1751},[249,9321,1755],{"class":1002},[249,9323,9324,9326],{"class":251,"line":277},[249,9325,1785],{"class":1002},[249,9327,1788],{"class":929},[249,9329,9330,9332],{"class":251,"line":283},[249,9331,1793],{"class":1751},[249,9333,1755],{"class":1002},[249,9335,9336,9338,9340,9342],{"class":251,"line":288},[249,9337,1785],{"class":1002},[249,9339,1109],{"class":1002},[249,9341,1804],{"class":929},[249,9343,1114],{"class":1002},[10,9345,1809,9346,1812],{},[172,9347,1735],{},[164,9349,9350],{"className":1671,"code":1815,"language":1673,"meta":170,"style":170},[172,9351,9352,9358],{"__ignoreMap":170},[249,9353,9354,9356],{"class":251,"line":252},[249,9355,1680],{"class":995},[249,9357,1683],{"class":929},[249,9359,9360,9362,9364,9366],{"class":251,"line":258},[249,9361,1828],{"class":925},[249,9363,1831],{"class":929},[249,9365,1834],{"class":929},[249,9367,1837],{"class":929},[10,9369,9370,1843,9372,1847,9374,1851],{},[172,9371,1842],{},[172,9373,1846],{},[172,9375,1850],{},[10,9377,1854,9378,1857],{},[172,9379,1735],{},[164,9381,9383],{"className":9382,"code":1861,"language":169,"meta":170},[167],[172,9384,1861],{"__ignoreMap":170},[10,9386,1866,9387,1870],{},[172,9388,1869],{},[164,9390,9392],{"className":9391,"code":1874,"language":169,"meta":170},[167],[172,9393,1874],{"__ignoreMap":170},[10,9395,1879,9396,1882,9398,761,9400,1887],{},[172,9397,1850],{},[172,9399,1735],{},[172,9401,1869],{},[164,9403,9405],{"className":9404,"code":1891,"language":169,"meta":170},[167],[172,9406,1891],{"__ignoreMap":170},[10,9408,1896],{},[10,9410,1899],{},[1901,9412,9413],{},[10,9414,1905],{},[10,9416,1908],{},[28,9418,1912],{"id":1911},[10,9420,1915],{},[164,9422,9423],{"className":1671,"code":1918,"language":1673,"meta":170,"style":170},[172,9424,9425,9431],{"__ignoreMap":170},[249,9426,9427,9429],{"class":251,"line":252},[249,9428,1680],{"class":995},[249,9430,1683],{"class":929},[249,9432,9433,9435,9437,9439,9441,9443],{"class":251,"line":258},[249,9434,1828],{"class":925},[249,9436,1831],{"class":929},[249,9438,1935],{"class":929},[249,9440,1938],{"class":929},[249,9442,1834],{"class":929},[249,9444,1837],{"class":929},[164,9446,9447],{"className":1671,"code":1945,"language":1673,"meta":170,"style":170},[172,9448,9449,9455],{"__ignoreMap":170},[249,9450,9451,9453],{"class":251,"line":252},[249,9452,1680],{"class":995},[249,9454,1954],{"class":929},[249,9456,9457,9459,9461,9463,9465,9467],{"class":251,"line":258},[249,9458,1828],{"class":925},[249,9460,1831],{"class":929},[249,9462,1935],{"class":929},[249,9464,1965],{"class":929},[249,9466,1834],{"class":929},[249,9468,1837],{"class":929},[10,9470,9471,1975],{},[172,9472,1974],{},[10,9474,1978,9475,1981],{},[172,9476,1842],{},[164,9478,9480],{"className":9479,"code":1985,"language":169,"meta":170},[167],[172,9481,1985],{"__ignoreMap":170},[10,9483,1990],{},[164,9485,9486],{"className":1742,"code":1993,"language":1744,"meta":170,"style":170},[172,9487,9488,9494,9500,9508,9514,9520,9526],{"__ignoreMap":170},[249,9489,9490,9492],{"class":251,"line":252},[249,9491,1752],{"class":1751},[249,9493,1755],{"class":1002},[249,9495,9496,9498],{"class":251,"line":258},[249,9497,1760],{"class":1751},[249,9499,1755],{"class":1002},[249,9501,9502,9504,9506],{"class":251,"line":265},[249,9503,1767],{"class":1751},[249,9505,1091],{"class":1002},[249,9507,1773],{"class":1772},[249,9509,9510,9512],{"class":251,"line":271},[249,9511,1778],{"class":1751},[249,9513,1755],{"class":1002},[249,9515,9516,9518],{"class":251,"line":277},[249,9517,1785],{"class":1002},[249,9519,1788],{"class":929},[249,9521,9522,9524],{"class":251,"line":283},[249,9523,1793],{"class":1751},[249,9525,1755],{"class":1002},[249,9527,9528,9530,9532,9534],{"class":251,"line":288},[249,9529,1785],{"class":1002},[249,9531,1109],{"class":1002},[249,9533,2042],{"class":929},[249,9535,1114],{"class":1002},[10,9537,2047],{},[164,9539,9540],{"className":1671,"code":2050,"language":1673,"meta":170,"style":170},[172,9541,9542,9546],{"__ignoreMap":170},[249,9543,9544],{"class":251,"line":252},[249,9545,2058],{"class":2057},[249,9547,9548,9550,9552,9554,9556,9558,9560,9562,9564],{"class":251,"line":258},[249,9549,2063],{"class":1173},[249,9551,1177],{"class":1002},[249,9553,2068],{"class":929},[249,9555,2071],{"class":925},[249,9557,1831],{"class":929},[249,9559,1935],{"class":929},[249,9561,1938],{"class":929},[249,9563,1834],{"class":929},[249,9565,1837],{"class":929},[164,9567,9568],{"className":1671,"code":2084,"language":1673,"meta":170,"style":170},[172,9569,9570,9574],{"__ignoreMap":170},[249,9571,9572],{"class":251,"line":252},[249,9573,2091],{"class":2057},[249,9575,9576,9578,9580,9582,9584,9586,9588,9590,9592],{"class":251,"line":258},[249,9577,2063],{"class":1173},[249,9579,1177],{"class":1002},[249,9581,2100],{"class":929},[249,9583,2071],{"class":925},[249,9585,1831],{"class":929},[249,9587,1935],{"class":929},[249,9589,1965],{"class":929},[249,9591,1834],{"class":929},[249,9593,1837],{"class":929},[10,9595,2115],{},[2117,9597,9598],{"title":2119,"type":2120},[10,9599,2123,9600,2126,9602,2130],{},[172,9601,1974],{},[172,9603,2129],{},[28,9605,2134],{"id":2133},[10,9607,2137],{},[164,9609,9611],{"className":9610,"code":2141,"language":169,"meta":170},[167],[172,9612,2141],{"__ignoreMap":170},[10,9614,2146],{},[164,9616,9617],{"className":1671,"code":2149,"language":1673,"meta":170,"style":170},[172,9618,9619],{"__ignoreMap":170},[249,9620,9621,9623,9625,9627,9629,9631],{"class":251,"line":252},[249,9622,1828],{"class":925},[249,9624,1831],{"class":929},[249,9626,1834],{"class":929},[249,9628,2162],{"class":929},[249,9630,2165],{"class":929},[249,9632,2168],{"class":929},[10,9634,2171],{},[164,9636,9637],{"className":1671,"code":2174,"language":1673,"meta":170,"style":170},[172,9638,9639,9645],{"__ignoreMap":170},[249,9640,9641,9643],{"class":251,"line":252},[249,9642,1680],{"class":995},[249,9644,1683],{"class":929},[249,9646,9647,9649,9651,9653],{"class":251,"line":258},[249,9648,2187],{"class":925},[249,9650,2190],{"class":929},[249,9652,2193],{"class":929},[249,9654,2196],{"class":1772},[164,9656,9657],{"className":1671,"code":2199,"language":1673,"meta":170,"style":170},[172,9658,9659,9665],{"__ignoreMap":170},[249,9660,9661,9663],{"class":251,"line":252},[249,9662,1680],{"class":995},[249,9664,1954],{"class":929},[249,9666,9667,9669,9671,9673],{"class":251,"line":258},[249,9668,2187],{"class":925},[249,9670,2190],{"class":929},[249,9672,2193],{"class":929},[249,9674,2218],{"class":1772},[10,9676,2221],{},[10,9678,2224],{},[28,9680,2228],{"id":2227},[404,9682,2231],{"id":2231},[10,9684,2234],{},[164,9686,9688],{"className":9687,"code":2238,"language":169,"meta":170},[167],[172,9689,2238],{"__ignoreMap":170},[10,9691,2243],{},[404,9693,2247],{"id":2246},[10,9695,2250],{},[164,9697,9698],{"className":1742,"code":2253,"language":1744,"meta":170,"style":170},[172,9699,9700,9706,9712,9718,9724,9728,9734],{"__ignoreMap":170},[249,9701,9702,9704],{"class":251,"line":252},[249,9703,1752],{"class":1751},[249,9705,1755],{"class":1002},[249,9707,9708,9710],{"class":251,"line":258},[249,9709,2266],{"class":1751},[249,9711,1755],{"class":1002},[249,9713,9714,9716],{"class":251,"line":265},[249,9715,1778],{"class":1751},[249,9717,1755],{"class":1002},[249,9719,9720,9722],{"class":251,"line":271},[249,9721,1785],{"class":1002},[249,9723,2281],{"class":929},[249,9725,9726],{"class":251,"line":277},[249,9727,262],{"emptyLinePlaceholder":261},[249,9729,9730,9732],{"class":251,"line":283},[249,9731,2290],{"class":1751},[249,9733,1755],{"class":1002},[249,9735,9736,9738],{"class":251,"line":288},[249,9737,2297],{"class":1751},[249,9739,1755],{"class":1002},[10,9741,2302,9742,2306],{},[172,9743,2305],{},[164,9745,9746],{"className":1742,"code":2309,"language":1744,"meta":170,"style":170},[172,9747,9748,9754,9760],{"__ignoreMap":170},[249,9749,9750,9752],{"class":251,"line":252},[249,9751,2290],{"class":1751},[249,9753,1755],{"class":1002},[249,9755,9756,9758],{"class":251,"line":258},[249,9757,2297],{"class":1751},[249,9759,1755],{"class":1002},[249,9761,9762,9764,9766],{"class":251,"line":265},[249,9763,2328],{"class":1751},[249,9765,1091],{"class":1002},[249,9767,2333],{"class":929},[10,9769,2336],{},[404,9771,2340],{"id":2339},[10,9773,2343],{},[10,9775,2346],{},[10,9777,2349],{},[470,9779,9780,9782,9784],{},[473,9781,2354],{},[473,9783,2357],{},[473,9785,2360],{},[10,9787,2363],{},[2117,9789,9790],{"title":2366,"type":2367},[10,9791,2370],{},[28,9793,2373],{"id":2373},[10,9795,2376],{},[38,9797,9798,9808],{},[41,9799,9800],{},[44,9801,9802,9804,9806],{},[47,9803,2385],{},[47,9805,2388],{},[47,9807,2391],{},[57,9809,9810,9818,9826],{},[44,9811,9812,9814,9816],{},[62,9813,2398],{},[62,9815,2401],{},[62,9817,2404],{},[44,9819,9820,9822,9824],{},[62,9821,2409],{},[62,9823,2412],{},[62,9825,2415],{},[44,9827,9828,9830,9832],{},[62,9829,2420],{},[62,9831,2423],{},[62,9833,2426],{},[10,9835,2429],{},[10,9837,2432],{},[28,9839,465],{"id":465},[10,9841,2437],{},[10,9843,2440],{},[10,9845,2443],{},[1901,9847,9848],{},[10,9849,1905],{},[10,9851,2450],{},[10,9853,2453,9854,2457],{},[17,9855,2456],{},[499,9857,2460],{},{"title":170,"searchDepth":258,"depth":258,"links":9859},[9860,9861,9862,9863,9864,9865,9870,9871],{"id":1620,"depth":258,"text":1621},{"id":1657,"depth":258,"text":1658},{"id":1728,"depth":258,"text":1729},{"id":1911,"depth":258,"text":1912},{"id":2133,"depth":258,"text":2134},{"id":2227,"depth":258,"text":2228,"children":9866},[9867,9868,9869],{"id":2231,"depth":265,"text":2231},{"id":2246,"depth":265,"text":2247},{"id":2339,"depth":265,"text":2340},{"id":2373,"depth":258,"text":2373},{"id":465,"depth":258,"text":465},{},{"title":685,"description":2475},[2481,2482],{"id":2486,"title":2487,"body":9876,"description":3154,"extension":517,"meta":10396,"navigation":261,"path":3156,"publishDate":3157,"published":261,"seo":10397,"stem":3159,"tags":10398,"thumbnail":3162,"updated":3163,"__hash__":3164},{"type":7,"value":9877,"toc":10376},[9878,9880,9884,9889,9891,9893,9901,9903,9905,9907,9909,9914,9916,9921,9931,9943,9948,9950,9952,9954,9959,9961,9963,9973,9975,9980,9982,10004,10006,10018,10024,10026,10040,10042,10050,10054,10056,10058,10086,10088,10090,10094,10096,10110,10115,10117,10119,10125,10127,10129,10141,10143,10148,10150,10152,10154,10202,10206,10208,10210,10264,10266,10268,10270,10274,10340,10342,10344,10346,10348,10366,10370,10374],[10,9879,12],{},[10,9881,2494,9882,2498],{},[172,9883,2497],{},[164,9885,9887],{"className":9886,"code":2502,"language":169,"meta":170},[167],[172,9888,2502],{"__ignoreMap":170},[10,9890,2507],{},[10,9892,2510],{},[2117,9894,9895],{"title":2513,"type":2367},[10,9896,2516,9897,2520,9899,2524],{},[172,9898,2519],{},[2522,9900],{},[28,9902,2527],{"id":2527},[10,9904,2530],{},[10,9906,2533],{},[404,9908,2536],{"id":2536},[164,9910,9912],{"className":9911,"code":2540,"language":169,"meta":170},[167],[172,9913,2540],{"__ignoreMap":170},[404,9915,2545],{"id":2545},[164,9917,9919],{"className":9918,"code":2549,"language":169,"meta":170},[167],[172,9920,2549],{"__ignoreMap":170},[10,9922,9923,2557,9925,2561,9927,2557,9929,2568],{},[172,9924,2556],{},[172,9926,2560],{},[172,9928,2564],{},[172,9930,2567],{},[10,9932,2571,9933,2557,9935,2576,9937,2579,9939,2557,9941,2584],{},[172,9934,2560],{},[172,9936,2567],{},[2522,9938],{},[172,9940,2556],{},[172,9942,2564],{},[164,9944,9946],{"className":9945,"code":2588,"language":169,"meta":170},[167],[172,9947,2588],{"__ignoreMap":170},[10,9949,2593],{},[28,9951,2596],{"id":2596},[10,9953,2599],{},[164,9955,9957],{"className":9956,"code":2603,"language":169,"meta":170},[167],[172,9958,2603],{"__ignoreMap":170},[10,9960,2608],{},[404,9962,2612],{"id":2611},[164,9964,9965],{"className":1671,"code":2615,"language":1673,"meta":170,"style":170},[172,9966,9967],{"__ignoreMap":170},[249,9968,9969,9971],{"class":251,"line":252},[249,9970,1688],{"class":925},[249,9972,2624],{"class":929},[10,9974,2627],{},[164,9976,9978],{"className":9977,"code":2631,"language":169,"meta":170},[167],[172,9979,2631],{"__ignoreMap":170},[10,9981,2636],{},[164,9983,9984],{"className":1671,"code":2639,"language":1673,"meta":170,"style":170},[172,9985,9986],{"__ignoreMap":170},[249,9987,9988,9990,9992,9994,9996,9998,10000,10002],{"class":251,"line":252},[249,9989,1688],{"class":925},[249,9991,2648],{"class":929},[249,9993,2651],{"class":929},[249,9995,2654],{"class":929},[249,9997,2657],{"class":929},[249,9999,1109],{"class":1002},[249,10001,2662],{"class":929},[249,10003,1114],{"class":1002},[404,10005,2668],{"id":2667},[164,10007,10008],{"className":1671,"code":2671,"language":1673,"meta":170,"style":170},[172,10009,10010],{"__ignoreMap":170},[249,10011,10012,10014,10016],{"class":251,"line":252},[249,10013,1688],{"class":925},[249,10015,2680],{"class":929},[249,10017,2683],{"class":929},[10,10019,10020,2689,10022,2692],{},[172,10021,2688],{},[2522,10023],{},[404,10025,2696],{"id":2695},[164,10027,10028],{"className":1671,"code":2699,"language":1673,"meta":170,"style":170},[172,10029,10030],{"__ignoreMap":170},[249,10031,10032,10034,10036,10038],{"class":251,"line":252},[249,10033,1688],{"class":925},[249,10035,2708],{"class":929},[249,10037,2711],{"class":929},[249,10039,2714],{"class":929},[10,10041,2717],{},[470,10043,10044,10046,10048],{},[473,10045,2722],{},[473,10047,2725],{},[473,10049,2728],{},[10,10051,2731,10052,2734],{},[172,10053,2519],{},[28,10055,2737],{"id":2737},[10,10057,2740],{},[164,10059,10060],{"className":1671,"code":2743,"language":1673,"meta":170,"style":170},[172,10061,10062,10068,10076],{"__ignoreMap":170},[249,10063,10064,10066],{"class":251,"line":252},[249,10065,1688],{"class":925},[249,10067,2624],{"class":929},[249,10069,10070,10072,10074],{"class":251,"line":258},[249,10071,1688],{"class":925},[249,10073,2680],{"class":929},[249,10075,2683],{"class":929},[249,10077,10078,10080,10082,10084],{"class":251,"line":265},[249,10079,1688],{"class":925},[249,10081,2708],{"class":929},[249,10083,2711],{"class":929},[249,10085,2714],{"class":929},[10,10087,2772],{},[28,10089,2776],{"id":2775},[10,10091,2779,10092,2783],{},[172,10093,2782],{},[10,10095,2786],{},[164,10097,10098],{"className":1671,"code":2789,"language":1673,"meta":170,"style":170},[172,10099,10100],{"__ignoreMap":170},[249,10101,10102,10104,10106,10108],{"class":251,"line":252},[249,10103,1688],{"class":925},[249,10105,2798],{"class":929},[249,10107,2801],{"class":929},[249,10109,2804],{"class":929},[164,10111,10113],{"className":10112,"code":2808,"language":169,"meta":170},[167],[172,10114,2808],{"__ignoreMap":170},[10,10116,2813],{},[10,10118,2816],{},[10,10120,2819,10121,2822,10123,2826],{},[172,10122,2688],{},[172,10124,2825],{},[28,10126,2830],{"id":2829},[10,10128,2833],{},[164,10130,10131],{"className":1671,"code":2836,"language":1673,"meta":170,"style":170},[172,10132,10133],{"__ignoreMap":170},[249,10134,10135,10137,10139],{"class":251,"line":252},[249,10136,1688],{"class":925},[249,10138,2651],{"class":929},[249,10140,2847],{"class":929},[10,10142,2850],{},[164,10144,10146],{"className":10145,"code":2854,"language":169,"meta":170},[167],[172,10147,2854],{"__ignoreMap":170},[28,10149,2859],{"id":2859},[404,10151,2862],{"id":2862},[10,10153,2865],{},[164,10155,10156],{"className":1671,"code":2868,"language":1673,"meta":170,"style":170},[172,10157,10158,10176,10184,10194],{"__ignoreMap":170},[249,10159,10160,10162,10164,10166,10168,10170,10172,10174],{"class":251,"line":252},[249,10161,1688],{"class":925},[249,10163,2648],{"class":929},[249,10165,2651],{"class":929},[249,10167,2654],{"class":929},[249,10169,2657],{"class":929},[249,10171,1109],{"class":1002},[249,10173,2662],{"class":929},[249,10175,1114],{"class":1002},[249,10177,10178,10180,10182],{"class":251,"line":258},[249,10179,1688],{"class":925},[249,10181,2680],{"class":929},[249,10183,2683],{"class":929},[249,10185,10186,10188,10190,10192],{"class":251,"line":265},[249,10187,1688],{"class":925},[249,10189,2708],{"class":929},[249,10191,2711],{"class":929},[249,10193,2714],{"class":929},[249,10195,10196,10198,10200],{"class":251,"line":271},[249,10197,1688],{"class":925},[249,10199,2648],{"class":929},[249,10201,2915],{"class":929},[10,10203,2918,10204,2922],{},[172,10205,2921],{},[404,10207,2925],{"id":2925},[10,10209,2928],{},[164,10211,10212],{"className":1671,"code":2931,"language":1673,"meta":170,"style":170},[172,10213,10214,10222,10232,10240,10250],{"__ignoreMap":170},[249,10215,10216,10218,10220],{"class":251,"line":252},[249,10217,1688],{"class":925},[249,10219,2680],{"class":929},[249,10221,2683],{"class":929},[249,10223,10224,10226,10228,10230],{"class":251,"line":258},[249,10225,1688],{"class":925},[249,10227,2948],{"class":929},[249,10229,2951],{"class":929},[249,10231,2954],{"class":929},[249,10233,10234,10236,10238],{"class":251,"line":265},[249,10235,1688],{"class":925},[249,10237,2961],{"class":929},[249,10239,2964],{"class":929},[249,10241,10242,10244,10246,10248],{"class":251,"line":271},[249,10243,1688],{"class":925},[249,10245,2708],{"class":929},[249,10247,2711],{"class":929},[249,10249,2714],{"class":929},[249,10251,10252,10254,10256,10258,10260,10262],{"class":251,"line":277},[249,10253,1688],{"class":925},[249,10255,2981],{"class":929},[249,10257,2984],{"class":1002},[249,10259,2987],{"class":929},[249,10261,2556],{"class":1173},[249,10263,2992],{"class":1002},[10,10265,2995],{},[28,10267,2999],{"id":2998},[10,10269,3002],{},[10,10271,3005,10272,3009],{},[172,10273,3008],{},[164,10275,10276],{"className":1671,"code":3012,"language":1673,"meta":170,"style":170},[172,10277,10278,10286,10296,10300,10308,10318,10322,10330],{"__ignoreMap":170},[249,10279,10280,10282,10284],{"class":251,"line":252},[249,10281,1688],{"class":925},[249,10283,3021],{"class":929},[249,10285,3024],{"class":929},[249,10287,10288,10290,10292,10294],{"class":251,"line":258},[249,10289,1688],{"class":925},[249,10291,2708],{"class":929},[249,10293,2711],{"class":929},[249,10295,3035],{"class":929},[249,10297,10298],{"class":251,"line":265},[249,10299,262],{"emptyLinePlaceholder":261},[249,10301,10302,10304,10306],{"class":251,"line":271},[249,10303,1688],{"class":925},[249,10305,3021],{"class":929},[249,10307,3048],{"class":929},[249,10309,10310,10312,10314,10316],{"class":251,"line":277},[249,10311,1688],{"class":925},[249,10313,2708],{"class":929},[249,10315,2711],{"class":929},[249,10317,3059],{"class":929},[249,10319,10320],{"class":251,"line":283},[249,10321,262],{"emptyLinePlaceholder":261},[249,10323,10324,10326,10328],{"class":251,"line":288},[249,10325,1688],{"class":925},[249,10327,3021],{"class":929},[249,10329,2804],{"class":929},[249,10331,10332,10334,10336,10338],{"class":251,"line":294},[249,10333,1688],{"class":925},[249,10335,2708],{"class":929},[249,10337,2711],{"class":929},[249,10339,2714],{"class":929},[10,10341,3084],{},[28,10343,465],{"id":465},[10,10345,3089],{},[10,10347,3092],{},[638,10349,10350,10354,10356,10360,10364],{},[473,10351,10352,3100],{},[172,10353,3099],{},[473,10355,3103],{},[473,10357,10358,3108],{},[172,10359,3008],{},[473,10361,10362,3114],{},[172,10363,3113],{},[473,10365,3117],{},[10,10367,3120,10368,3123],{},[2522,10369],{},[10,10371,3126,10372,3130],{},[17,10373,3129],{},[499,10375,3133],{},{"title":170,"searchDepth":258,"depth":258,"links":10377},[10378,10382,10387,10388,10389,10390,10394,10395],{"id":2527,"depth":258,"text":2527,"children":10379},[10380,10381],{"id":2536,"depth":265,"text":2536},{"id":2545,"depth":265,"text":2545},{"id":2596,"depth":258,"text":2596,"children":10383},[10384,10385,10386],{"id":2611,"depth":265,"text":2612},{"id":2667,"depth":265,"text":2668},{"id":2695,"depth":265,"text":2696},{"id":2737,"depth":258,"text":2737},{"id":2775,"depth":258,"text":2776},{"id":2829,"depth":258,"text":2830},{"id":2859,"depth":258,"text":2859,"children":10391},[10392,10393],{"id":2862,"depth":265,"text":2862},{"id":2925,"depth":265,"text":2925},{"id":2998,"depth":258,"text":2999},{"id":465,"depth":258,"text":465},{},{"title":2487,"description":3154},[2481,3161],{"id":3166,"title":3167,"body":10400,"description":3769,"extension":517,"meta":10860,"navigation":261,"path":3771,"publishDate":3772,"published":261,"seo":10861,"stem":3774,"tags":10862,"thumbnail":3777,"updated":3772,"__hash__":3778},{"type":7,"value":10401,"toc":10850},[10402,10404,10408,10410,10414,10416,10420,10422,10424,10429,10431,10436,10438,10440,10442,10468,10474,10478,10483,10487,10513,10517,10522,10526,10552,10554,10559,10561,10563,10565,10567,10579,10581,10586,10588,10618,10622,10624,10626,10640,10644,10646,10651,10653,10655,10657,10667,10669,10681,10683,10688,10692,10694,10696,10710,10712,10717,10719,10721,10729,10735,10737,10742,10744,10756,10758,10760,10762,10800,10802,10806,10808,10810,10830,10832,10834,10846,10848],[10,10403,12],{},[10,10405,3174,10406,3178],{},[17,10407,3177],{},[10,10409,3181],{},[10,10411,3184,10412,3188],{},[17,10413,3187],{},[10,10415,3191],{},[2117,10417,10418],{"title":3194,"type":2367},[10,10419,3197],{},[28,10421,3201],{"id":3200},[10,10423,3204],{},[164,10425,10427],{"className":10426,"code":3208,"language":169,"meta":170},[167],[172,10428,3208],{"__ignoreMap":170},[10,10430,3213],{},[164,10432,10434],{"className":10433,"code":3217,"language":169,"meta":170},[167],[172,10435,3217],{"__ignoreMap":170},[10,10437,3222],{},[28,10439,3225],{"id":3225},[10,10441,3228],{},[164,10443,10444],{"className":1671,"code":3231,"language":1673,"meta":170,"style":170},[172,10445,10446],{"__ignoreMap":170},[249,10447,10448,10450,10452,10454,10456,10458,10460,10462,10464,10466],{"class":251,"line":252},[249,10449,3238],{"class":925},[249,10451,3241],{"class":929},[249,10453,2162],{"class":929},[249,10455,3246],{"class":1772},[249,10457,3249],{"class":929},[249,10459,3252],{"class":1002},[249,10461,3255],{"class":929},[249,10463,3258],{"class":1002},[249,10465,3261],{"class":925},[249,10467,3264],{"class":929},[10,10469,10470,3269,10472,3273],{},[172,10471,3238],{},[172,10473,3272],{},[10,10475,3276,10476,3280],{},[172,10477,3279],{},[164,10479,10481],{"className":10480,"code":3284,"language":169,"meta":170},[167],[172,10482,3284],{"__ignoreMap":170},[10,10484,3289,10485,3292],{},[172,10486,3279],{},[164,10488,10489],{"className":1671,"code":3295,"language":1673,"meta":170,"style":170},[172,10490,10491],{"__ignoreMap":170},[249,10492,10493,10495,10497,10499,10501,10503,10505,10507,10509,10511],{"class":251,"line":252},[249,10494,3238],{"class":925},[249,10496,3241],{"class":929},[249,10498,2162],{"class":929},[249,10500,3246],{"class":1772},[249,10502,3310],{"class":929},[249,10504,3252],{"class":1002},[249,10506,3255],{"class":929},[249,10508,3258],{"class":1002},[249,10510,3261],{"class":925},[249,10512,3264],{"class":929},[10,10514,3323,10515,3327],{},[172,10516,3326],{},[164,10518,10520],{"className":10519,"code":3331,"language":169,"meta":170},[167],[172,10521,3331],{"__ignoreMap":170},[10,10523,3336,10524,3339],{},[172,10525,3326],{},[164,10527,10528],{"className":1671,"code":3342,"language":1673,"meta":170,"style":170},[172,10529,10530],{"__ignoreMap":170},[249,10531,10532,10534,10536,10538,10540,10542,10544,10546,10548,10550],{"class":251,"line":252},[249,10533,3238],{"class":925},[249,10535,3241],{"class":929},[249,10537,2162],{"class":929},[249,10539,3246],{"class":1772},[249,10541,3357],{"class":929},[249,10543,3252],{"class":1002},[249,10545,3255],{"class":929},[249,10547,3258],{"class":1002},[249,10549,3261],{"class":925},[249,10551,3264],{"class":929},[10,10553,3370],{},[164,10555,10557],{"className":10556,"code":3374,"language":169,"meta":170},[167],[172,10558,3374],{"__ignoreMap":170},[10,10560,3379],{},[10,10562,3382],{},[28,10564,3386],{"id":3385},[10,10566,3389],{},[164,10568,10569],{"className":1671,"code":3392,"language":1673,"meta":170,"style":170},[172,10570,10571],{"__ignoreMap":170},[249,10572,10573,10575,10577],{"class":251,"line":252},[249,10574,1828],{"class":925},[249,10576,3401],{"class":929},[249,10578,3404],{"class":929},[10,10580,3407],{},[164,10582,10584],{"className":10583,"code":3411,"language":169,"meta":170},[167],[172,10585,3411],{"__ignoreMap":170},[10,10587,3416],{},[38,10589,10590,10598],{},[41,10591,10592],{},[44,10593,10594,10596],{},[47,10595,834],{},[47,10597,3428],{"align":3427},[57,10599,10600,10606,10612],{},[44,10601,10602,10604],{},[62,10603,3435],{},[62,10605,3438],{"align":3427},[44,10607,10608,10610],{},[62,10609,3443],{},[62,10611,3446],{"align":3427},[44,10613,10614,10616],{},[62,10615,3451],{},[62,10617,3454],{"align":3427},[10,10619,10620,3460],{},[172,10621,3459],{},[28,10623,3464],{"id":3463},[10,10625,3467],{},[164,10627,10628],{"className":1671,"code":3470,"language":1673,"meta":170,"style":170},[172,10629,10630],{"__ignoreMap":170},[249,10631,10632,10634,10636,10638],{"class":251,"line":252},[249,10633,1828],{"class":925},[249,10635,3479],{"class":929},[249,10637,3482],{"class":929},[249,10639,3485],{"class":929},[10,10641,10642,3491],{},[172,10643,3490],{},[10,10645,3494],{},[164,10647,10649],{"className":10648,"code":3498,"language":169,"meta":170},[167],[172,10650,3498],{"__ignoreMap":170},[10,10652,3503],{},[28,10654,3507],{"id":3506},[10,10656,3510],{},[164,10658,10659],{"className":1671,"code":3513,"language":1673,"meta":170,"style":170},[172,10660,10661],{"__ignoreMap":170},[249,10662,10663,10665],{"class":251,"line":252},[249,10664,1828],{"class":925},[249,10666,3522],{"class":929},[10,10668,3525],{},[164,10670,10671],{"className":1671,"code":3528,"language":1673,"meta":170,"style":170},[172,10672,10673],{"__ignoreMap":170},[249,10674,10675,10677,10679],{"class":251,"line":252},[249,10676,1828],{"class":925},[249,10678,3537],{"class":929},[249,10680,3540],{"class":929},[10,10682,3543],{},[164,10684,10686],{"className":10685,"code":3547,"language":169,"meta":170},[167],[172,10687,3547],{"__ignoreMap":170},[10,10689,3552,10690,3556],{},[172,10691,3555],{},[28,10693,3560],{"id":3559},[10,10695,3563],{},[164,10697,10698],{"className":1671,"code":3566,"language":1673,"meta":170,"style":170},[172,10699,10700],{"__ignoreMap":170},[249,10701,10702,10704,10706,10708],{"class":251,"line":252},[249,10703,1828],{"class":925},[249,10705,3401],{"class":929},[249,10707,3577],{"class":929},[249,10709,3580],{"class":929},[10,10711,3583],{},[164,10713,10715],{"className":10714,"code":3587,"language":169,"meta":170},[167],[172,10716,3587],{"__ignoreMap":170},[10,10718,3592],{},[10,10720,3595],{},[164,10722,10723],{"className":243,"code":3598,"language":245,"meta":170,"style":170},[172,10724,10725],{"__ignoreMap":170},[249,10726,10727],{"class":251,"line":252},[249,10728,3598],{},[2117,10730,10731],{"title":3607,"type":2367},[10,10732,10733,3613],{},[172,10734,3612],{},[10,10736,3616],{},[164,10738,10740],{"className":10739,"code":3620,"language":169,"meta":170},[167],[172,10741,3620],{"__ignoreMap":170},[10,10743,3625],{},[164,10745,10746],{"className":1671,"code":3628,"language":1673,"meta":170,"style":170},[172,10747,10748],{"__ignoreMap":170},[249,10749,10750,10752,10754],{"class":251,"line":252},[249,10751,1828],{"class":925},[249,10753,3637],{"class":929},[249,10755,3540],{"class":929},[10,10757,3642],{},[28,10759,3645],{"id":3645},[10,10761,3648],{},[38,10763,10764,10774],{},[41,10765,10766],{},[44,10767,10768,10770,10772],{},[47,10769,834],{},[47,10771,3659],{"align":3427},[47,10773,3662],{"align":3427},[57,10775,10776,10784,10792],{},[44,10777,10778,10780,10782],{},[62,10779,3435],{},[62,10781,3438],{"align":3427},[62,10783,3673],{"align":3427},[44,10785,10786,10788,10790],{},[62,10787,3443],{},[62,10789,3446],{"align":3427},[62,10791,3682],{"align":3427},[44,10793,10794,10796,10798],{},[62,10795,3451],{},[62,10797,3454],{"align":3427},[62,10799,3691],{"align":3427},[10,10801,3694],{},[10,10803,3697,10804,3701],{},[172,10805,3700],{},[28,10807,465],{"id":465},[10,10809,3706],{},[638,10811,10812,10818,10822,10826,10828],{},[473,10813,10814,3713,10816,3716],{},[172,10815,3238],{},[172,10817,3279],{},[473,10819,10820,3722],{},[172,10821,3721],{},[473,10823,3725,10824,3728],{},[172,10825,3459],{},[473,10827,3731],{},[473,10829,3734],{},[10,10831,3737],{},[10,10833,3740],{},[164,10835,10836],{"className":1671,"code":3392,"language":1673,"meta":170,"style":170},[172,10837,10838],{"__ignoreMap":170},[249,10839,10840,10842,10844],{"class":251,"line":252},[249,10841,1828],{"class":925},[249,10843,3401],{"class":929},[249,10845,3404],{"class":929},[10,10847,3755],{},[499,10849,3758],{},{"title":170,"searchDepth":258,"depth":258,"links":10851},[10852,10853,10854,10855,10856,10857,10858,10859],{"id":3200,"depth":258,"text":3201},{"id":3225,"depth":258,"text":3225},{"id":3385,"depth":258,"text":3386},{"id":3463,"depth":258,"text":3464},{"id":3506,"depth":258,"text":3507},{"id":3559,"depth":258,"text":3560},{"id":3645,"depth":258,"text":3645},{"id":465,"depth":258,"text":465},{},{"title":3167,"description":3769},[3776,2482],{"id":3780,"title":3781,"body":10864,"description":4475,"extension":517,"meta":11405,"navigation":261,"path":4477,"publishDate":4478,"published":261,"seo":11406,"stem":4480,"tags":11407,"thumbnail":4483,"updated":4478,"__hash__":4484},{"type":7,"value":10865,"toc":11390},[10866,10868,10870,10872,10874,10914,10916,10918,10978,10988,11000,11010,11022,11024,11026,11058,11064,11068,11076,11100,11110,11112,11124,11126,11130,11178,11180,11184,11212,11218,11220,11226,11242,11244,11250,11282,11284,11304,11308,11312,11320,11344,11358,11360,11364,11366,11378,11380,11382,11388],[10,10867,12],{},[10,10869,3788],{},[28,10871,3791],{"id":3791},[10,10873,3794],{},[164,10875,10876],{"className":3797,"code":3798,"language":3799,"meta":170,"style":170},[172,10877,10878,10882,10886,10890,10894,10898,10902,10906,10910],{"__ignoreMap":170},[249,10879,10880],{"class":251,"line":252},[249,10881,3806],{},[249,10883,10884],{"class":251,"line":258},[249,10885,3811],{},[249,10887,10888],{"class":251,"line":265},[249,10889,3816],{},[249,10891,10892],{"class":251,"line":271},[249,10893,1124],{},[249,10895,10896],{"class":251,"line":277},[249,10897,262],{"emptyLinePlaceholder":261},[249,10899,10900],{"class":251,"line":283},[249,10901,3829],{},[249,10903,10904],{"class":251,"line":288},[249,10905,262],{"emptyLinePlaceholder":261},[249,10907,10908],{"class":251,"line":294},[249,10909,3838],{},[249,10911,10912],{"class":251,"line":300},[249,10913,3843],{},[404,10915,3846],{"id":3846},[10,10917,3849],{},[164,10919,10920],{"className":3797,"code":3852,"language":3799,"meta":170,"style":170},[172,10921,10922,10926,10930,10934,10938,10942,10946,10950,10954,10958,10962,10966,10970,10974],{"__ignoreMap":170},[249,10923,10924],{"class":251,"line":252},[249,10925,3806],{},[249,10927,10928],{"class":251,"line":258},[249,10929,3811],{},[249,10931,10932],{"class":251,"line":265},[249,10933,3867],{},[249,10935,10936],{"class":251,"line":271},[249,10937,3872],{},[249,10939,10940],{"class":251,"line":277},[249,10941,3877],{},[249,10943,10944],{"class":251,"line":283},[249,10945,1124],{},[249,10947,10948],{"class":251,"line":288},[249,10949,262],{"emptyLinePlaceholder":261},[249,10951,10952],{"class":251,"line":294},[249,10953,3890],{},[249,10955,10956],{"class":251,"line":300},[249,10957,3895],{},[249,10959,10960],{"class":251,"line":306},[249,10961,3900],{},[249,10963,10964],{"class":251,"line":311},[249,10965,3905],{},[249,10967,10968],{"class":251,"line":317},[249,10969,262],{"emptyLinePlaceholder":261},[249,10971,10972],{"class":251,"line":323},[249,10973,3838],{},[249,10975,10976],{"class":251,"line":329},[249,10977,3843],{},[10,10979,3920,10980,3924,10982,144,10984,3931,10986,3934],{},[172,10981,3923],{},[172,10983,3927],{},[172,10985,3930],{},[172,10987,3927],{},[164,10989,10990],{"className":3797,"code":3937,"language":3799,"meta":170,"style":170},[172,10991,10992,10996],{"__ignoreMap":170},[249,10993,10994],{"class":251,"line":252},[249,10995,3944],{},[249,10997,10998],{"class":251,"line":258},[249,10999,3949],{},[2117,11001,11002],{"title":3952,"type":2120},[10,11003,11004,3957,11006,3960,11008,3963],{},[172,11005,3930],{},[172,11007,3927],{},[172,11009,3930],{},[164,11011,11012],{"className":3797,"code":3966,"language":3799,"meta":170,"style":170},[172,11013,11014,11018],{"__ignoreMap":170},[249,11015,11016],{"class":251,"line":252},[249,11017,3973],{},[249,11019,11020],{"class":251,"line":258},[249,11021,3978],{},[404,11023,3981],{"id":3981},[10,11025,3984],{},[164,11027,11028],{"className":3797,"code":3987,"language":3799,"meta":170,"style":170},[172,11029,11030,11034,11038,11042,11046,11050,11054],{"__ignoreMap":170},[249,11031,11032],{"class":251,"line":252},[249,11033,3806],{},[249,11035,11036],{"class":251,"line":258},[249,11037,3998],{},[249,11039,11040],{"class":251,"line":265},[249,11041,1124],{},[249,11043,11044],{"class":251,"line":271},[249,11045,262],{"emptyLinePlaceholder":261},[249,11047,11048],{"class":251,"line":277},[249,11049,4011],{},[249,11051,11052],{"class":251,"line":283},[249,11053,262],{"emptyLinePlaceholder":261},[249,11055,11056],{"class":251,"line":288},[249,11057,4020],{},[10,11059,4023,11060,4026,11062,144],{},[172,11061,2305],{},[172,11063,4029],{},[28,11065,4033,11066,4037],{"id":4032},[172,11067,4036],{},[10,11069,4040,11070,4044,11072,4048,11074,4051],{},[172,11071,4043],{},[172,11073,4047],{},[172,11075,4047],{},[164,11077,11078],{"className":3797,"code":4054,"language":3799,"meta":170,"style":170},[172,11079,11080,11084,11088,11092,11096],{"__ignoreMap":170},[249,11081,11082],{"class":251,"line":252},[249,11083,3806],{},[249,11085,11086],{"class":251,"line":258},[249,11087,3998],{},[249,11089,11090],{"class":251,"line":265},[249,11091,1124],{},[249,11093,11094],{"class":251,"line":271},[249,11095,262],{"emptyLinePlaceholder":261},[249,11097,11098],{"class":251,"line":277},[249,11099,4077],{},[10,11101,11102,4083,11104,4086,11106,4089,11108,4093],{},[172,11103,4082],{},[172,11105,4047],{},[172,11107,4036],{},[172,11109,4092],{},[10,11111,4096],{},[164,11113,11114],{"className":3797,"code":4099,"language":3799,"meta":170,"style":170},[172,11115,11116,11120],{"__ignoreMap":170},[249,11117,11118],{"class":251,"line":252},[249,11119,4106],{},[249,11121,11122],{"class":251,"line":258},[249,11123,4111],{},[404,11125,4114],{"id":4114},[10,11127,4117,11128,4121],{},[172,11129,4120],{},[164,11131,11132],{"className":3797,"code":4124,"language":3799,"meta":170,"style":170},[172,11133,11134,11138,11142,11146,11150,11154,11158,11162,11166,11170,11174],{"__ignoreMap":170},[249,11135,11136],{"class":251,"line":252},[249,11137,4131],{},[249,11139,11140],{"class":251,"line":258},[249,11141,4136],{},[249,11143,11144],{"class":251,"line":265},[249,11145,4141],{},[249,11147,11148],{"class":251,"line":271},[249,11149,4146],{},[249,11151,11152],{"class":251,"line":277},[249,11153,262],{"emptyLinePlaceholder":261},[249,11155,11156],{"class":251,"line":283},[249,11157,4155],{},[249,11159,11160],{"class":251,"line":288},[249,11161,4160],{},[249,11163,11164],{"class":251,"line":294},[249,11165,262],{"emptyLinePlaceholder":261},[249,11167,11168],{"class":251,"line":300},[249,11169,4169],{},[249,11171,11172],{"class":251,"line":306},[249,11173,262],{"emptyLinePlaceholder":261},[249,11175,11176],{"class":251,"line":311},[249,11177,4178],{},[404,11179,4181],{"id":4181},[10,11181,4184,11182,4188],{},[172,11183,4187],{},[164,11185,11186],{"className":3797,"code":4191,"language":3799,"meta":170,"style":170},[172,11187,11188,11192,11196,11200,11204,11208],{"__ignoreMap":170},[249,11189,11190],{"class":251,"line":252},[249,11191,4198],{},[249,11193,11194],{"class":251,"line":258},[249,11195,4203],{},[249,11197,11198],{"class":251,"line":265},[249,11199,1124],{},[249,11201,11202],{"class":251,"line":271},[249,11203,262],{"emptyLinePlaceholder":261},[249,11205,11206],{"class":251,"line":277},[249,11207,4216],{},[249,11209,11210],{"class":251,"line":283},[249,11211,4221],{},[10,11213,4224,11214,4228,11216,4231],{},[172,11215,4227],{},[172,11217,4187],{},[404,11219,4235],{"id":4234},[10,11221,11222,4241,11224,4244],{},[172,11223,4240],{},[172,11225,4043],{},[164,11227,11228],{"className":3797,"code":4247,"language":3799,"meta":170,"style":170},[172,11229,11230,11234,11238],{"__ignoreMap":170},[249,11231,11232],{"class":251,"line":252},[249,11233,4254],{},[249,11235,11236],{"class":251,"line":258},[249,11237,262],{"emptyLinePlaceholder":261},[249,11239,11240],{"class":251,"line":265},[249,11241,4263],{},[404,11243,4266],{"id":4266},[10,11245,4269,11246,4044,11248,4274],{},[172,11247,4043],{},[172,11249,4047],{},[164,11251,11252],{"className":3797,"code":4277,"language":3799,"meta":170,"style":170},[172,11253,11254,11258,11262,11266,11270,11274,11278],{"__ignoreMap":170},[249,11255,11256],{"class":251,"line":252},[249,11257,4284],{},[249,11259,11260],{"class":251,"line":258},[249,11261,4289],{},[249,11263,11264],{"class":251,"line":265},[249,11265,262],{"emptyLinePlaceholder":261},[249,11267,11268],{"class":251,"line":271},[249,11269,4298],{},[249,11271,11272],{"class":251,"line":277},[249,11273,262],{"emptyLinePlaceholder":261},[249,11275,11276],{"class":251,"line":283},[249,11277,4307],{},[249,11279,11280],{"class":251,"line":288},[249,11281,4312],{},[10,11283,4315],{},[164,11285,11286],{"className":3797,"code":4318,"language":3799,"meta":170,"style":170},[172,11287,11288,11292,11296,11300],{"__ignoreMap":170},[249,11289,11290],{"class":251,"line":252},[249,11291,4325],{},[249,11293,11294],{"class":251,"line":258},[249,11295,262],{"emptyLinePlaceholder":261},[249,11297,11298],{"class":251,"line":265},[249,11299,4334],{},[249,11301,11302],{"class":251,"line":271},[249,11303,4339],{},[10,11305,4342,11306,4346],{},[172,11307,4345],{},[28,11309,11310,4349],{"id":4349},[172,11311,4352],{},[10,11313,4355,11314,4044,11316,4360,11318,4363],{},[172,11315,4043],{},[172,11317,4047],{},[172,11319,4352],{},[164,11321,11322],{"className":3797,"code":4366,"language":3799,"meta":170,"style":170},[172,11323,11324,11328,11332,11336,11340],{"__ignoreMap":170},[249,11325,11326],{"class":251,"line":252},[249,11327,4373],{},[249,11329,11330],{"class":251,"line":258},[249,11331,262],{"emptyLinePlaceholder":261},[249,11333,11334],{"class":251,"line":265},[249,11335,4382],{},[249,11337,11338],{"class":251,"line":271},[249,11339,262],{"emptyLinePlaceholder":261},[249,11341,11342],{"class":251,"line":277},[249,11343,4391],{},[10,11345,11346,4083,11348,4400,11350,4404,11352,4407,11354,4044,11356,4412],{},[172,11347,4396],{},[172,11349,4399],{},[172,11351,4403],{},[172,11353,4352],{},[172,11355,4043],{},[172,11357,4047],{},[28,11359,4415],{"id":4415},[10,11361,4418,11362,4421],{},[172,11363,4047],{},[10,11365,4424],{},[470,11367,11368,11372,11374],{},[473,11369,4429,11370,4432],{},[172,11371,4036],{},[473,11373,4435],{},[473,11375,4438,11376,4441],{},[172,11377,4352],{},[28,11379,465],{"id":465},[10,11381,4446],{},[10,11383,4449,11384,4452,11386,4455],{},[172,11385,4043],{},[172,11387,4047],{},[499,11389,501],{},{"title":170,"searchDepth":258,"depth":258,"links":11391},[11392,11396,11402,11403,11404],{"id":3791,"depth":258,"text":3791,"children":11393},[11394,11395],{"id":3846,"depth":265,"text":3846},{"id":3981,"depth":265,"text":3981},{"id":4032,"depth":258,"text":4465,"children":11397},[11398,11399,11400,11401],{"id":4114,"depth":265,"text":4114},{"id":4181,"depth":265,"text":4181},{"id":4234,"depth":265,"text":4235},{"id":4266,"depth":265,"text":4266},{"id":4349,"depth":258,"text":4472},{"id":4415,"depth":258,"text":4415},{"id":465,"depth":258,"text":465},{},{"title":3781,"description":4475},[4482],{"id":4486,"title":4487,"body":11409,"description":6124,"extension":517,"meta":12752,"navigation":261,"path":6126,"publishDate":6127,"published":261,"seo":12753,"stem":6129,"tags":12754,"thumbnail":6131,"updated":6127,"__hash__":6132},{"type":7,"value":11410,"toc":12724},[11411,11413,11418,11428,11430,11434,11440,11464,11466,11470,11472,11474,11476,11512,11514,11516,11518,11524,11526,11528,11532,11538,11702,11710,11712,11714,11792,11794,11796,11864,11866,11868,11890,11892,11894,11900,12022,12024,12026,12028,12030,12032,12038,12046,12112,12116,12120,12124,12160,12164,12166,12168,12224,12228,12230,12234,12332,12338,12342,12346,12400,12402,12404,12406,12494,12496,12500,12516,12522,12524,12526,12598,12602,12604,12606,12714,12716,12718,12720,12722],[10,11412,12],{},[10,11414,4494,11415,4500],{},[151,11416,4499],{"href":4497,"rel":11417},[155],[470,11419,11420,11422,11424,11426],{},[473,11421,4505],{},[473,11423,4482],{},[473,11425,4510],{},[473,11427,4513],{},[28,11429,4505],{"id":4516},[404,11431,11432,4523],{"id":4519},[172,11433,4522],{},[10,11435,11436,4528,11438,4532],{},[172,11437,4522],{},[172,11439,4531],{},[164,11441,11442],{"className":4535,"code":4536,"language":4516,"meta":170,"style":170},[172,11443,11444],{"__ignoreMap":170},[249,11445,11446,11448,11450,11452,11454,11456,11458,11460,11462],{"class":251,"line":252},[249,11447,4543],{"class":1002},[249,11449,4546],{"class":1751},[249,11451,4549],{"class":1085},[249,11453,1177],{"class":1002},[249,11455,1088],{"class":1002},[249,11457,169],{"class":929},[249,11459,1088],{"class":1002},[249,11461,4560],{"class":1085},[249,11463,2992],{"class":1002},[10,11465,4565],{},[2117,11467,11468],{"title":4568,"type":2367},[10,11469,4571],{},[28,11471,4482],{"id":3799},[404,11473,4576],{"id":4576},[10,11475,4579],{},[164,11477,11478],{"className":3797,"code":4582,"language":3799,"meta":170,"style":170},[172,11479,11480,11484,11488,11492,11496,11500,11504,11508],{"__ignoreMap":170},[249,11481,11482],{"class":251,"line":252},[249,11483,4589],{},[249,11485,11486],{"class":251,"line":258},[249,11487,262],{"emptyLinePlaceholder":261},[249,11489,11490],{"class":251,"line":265},[249,11491,4598],{},[249,11493,11494],{"class":251,"line":271},[249,11495,4603],{},[249,11497,11498],{"class":251,"line":277},[249,11499,1124],{},[249,11501,11502],{"class":251,"line":283},[249,11503,262],{"emptyLinePlaceholder":261},[249,11505,11506],{"class":251,"line":288},[249,11507,4616],{},[249,11509,11510],{"class":251,"line":294},[249,11511,4621],{},[10,11513,4624],{},[404,11515,4628],{"id":4627},[10,11517,4631],{},[10,11519,4634,11520,3924,11522,4641],{},[172,11521,4637],{},[172,11523,4640],{},[10,11525,4644],{},[28,11527,4510],{"id":4647},[404,11529,11530],{"id":4650},[172,11531,4653],{},[10,11533,11534,4658,11536,4662],{},[172,11535,4653],{},[172,11537,4661],{},[164,11539,11540],{"className":4665,"code":4666,"language":4667,"meta":170,"style":170},[172,11541,11542,11560,11578,11592,11596,11620,11624,11636,11654,11658,11662,11674,11682,11690,11698],{"__ignoreMap":170},[249,11543,11544,11546,11548,11550,11552,11554,11556,11558],{"class":251,"line":252},[249,11545,4637],{"class":4674},[249,11547,4677],{"class":1002},[249,11549,4680],{"class":1173},[249,11551,4683],{"class":1002},[249,11553,4686],{"class":4674},[249,11555,1003],{"class":1002},[249,11557,4647],{"class":929},[249,11559,1009],{"class":1002},[249,11561,11562,11564,11566,11568,11570,11572,11574,11576],{"class":251,"line":258},[249,11563,4637],{"class":4674},[249,11565,4677],{"class":1002},[249,11567,4701],{"class":1173},[249,11569,4683],{"class":1002},[249,11571,4686],{"class":4674},[249,11573,1003],{"class":1002},[249,11575,4710],{"class":929},[249,11577,1009],{"class":1002},[249,11579,11580,11582,11584,11586,11588,11590],{"class":251,"line":265},[249,11581,4637],{"class":4674},[249,11583,4719],{"class":1173},[249,11585,4722],{"class":4674},[249,11587,1003],{"class":1002},[249,11589,4727],{"class":929},[249,11591,1009],{"class":1002},[249,11593,11594],{"class":251,"line":271},[249,11595,262],{"emptyLinePlaceholder":261},[249,11597,11598,11600,11602,11604,11606,11608,11610,11612,11614,11616,11618],{"class":251,"line":277},[249,11599,4738],{"class":1085},[249,11601,4741],{"class":1173},[249,11603,1177],{"class":1002},[249,11605,4746],{"class":1173},[249,11607,1846],{"class":1002},[249,11609,4751],{"class":995},[249,11611,4754],{"class":1173},[249,11613,4757],{"class":1002},[249,11615,4760],{"class":929},[249,11617,4757],{"class":1002},[249,11619,4765],{"class":1173},[249,11621,11622],{"class":251,"line":283},[249,11623,262],{"emptyLinePlaceholder":261},[249,11625,11626,11628,11630,11632,11634],{"class":251,"line":288},[249,11627,4774],{"class":4674},[249,11629,4777],{"class":1173},[249,11631,4780],{"class":1002},[249,11633,4783],{"class":1173},[249,11635,1077],{"class":1002},[249,11637,11638,11640,11642,11644,11646,11648,11650,11652],{"class":251,"line":294},[249,11639,4790],{"class":4674},[249,11641,4793],{"class":1002},[249,11643,4796],{"class":995},[249,11645,4754],{"class":1751},[249,11647,4757],{"class":1002},[249,11649,4803],{"class":929},[249,11651,4757],{"class":1002},[249,11653,4765],{"class":1751},[249,11655,11656],{"class":251,"line":300},[249,11657,1124],{"class":1002},[249,11659,11660],{"class":251,"line":306},[249,11661,262],{"emptyLinePlaceholder":261},[249,11663,11664,11666,11668,11670,11672],{"class":251,"line":311},[249,11665,4653],{"class":995},[249,11667,4822],{"class":1173},[249,11669,1846],{"class":1002},[249,11671,4661],{"class":995},[249,11673,4829],{"class":1173},[249,11675,11676,11678,11680],{"class":251,"line":317},[249,11677,4834],{"class":1002},[249,11679,4837],{"class":925},[249,11681,2992],{"class":1002},[249,11683,11684,11686,11688],{"class":251,"line":323},[249,11685,4844],{"class":1002},[249,11687,4847],{"class":925},[249,11689,4850],{"class":1002},[249,11691,11692,11694,11696],{"class":251,"line":329},[249,11693,4855],{"class":1002},[249,11695,4837],{"class":925},[249,11697,4860],{"class":1002},[249,11699,11700],{"class":251,"line":334},[249,11701,4765],{"class":1173},[10,11703,11704,4869,11706,4872,11708,4188],{},[172,11705,4653],{},[172,11707,4653],{},[172,11709,4875],{},[404,11711,4878],{"id":4878},[10,11713,4881],{},[164,11715,11716],{"className":4665,"code":4884,"language":4667,"meta":170,"style":170},[172,11717,11718,11728,11742,11754,11774,11782,11788],{"__ignoreMap":170},[249,11719,11720,11722,11724,11726],{"class":251,"line":252},[249,11721,4891],{"class":995},[249,11723,4754],{"class":1173},[249,11725,4897],{"class":4896},[249,11727,4900],{"class":1085},[249,11729,11730,11732,11734,11736,11738,11740],{"class":251,"line":258},[249,11731,4905],{"class":1173},[249,11733,1846],{"class":1002},[249,11735,4910],{"class":995},[249,11737,4754],{"class":1173},[249,11739,4915],{"class":4896},[249,11741,4900],{"class":1085},[249,11743,11744,11746,11748,11750,11752],{"class":251,"line":265},[249,11745,4922],{"class":1173},[249,11747,1846],{"class":1002},[249,11749,4927],{"class":1173},[249,11751,4930],{"class":1002},[249,11753,4933],{"class":1173},[249,11755,11756,11758,11760,11762,11764,11766,11768,11770,11772],{"class":251,"line":271},[249,11757,4938],{"class":1002},[249,11759,4677],{"class":1002},[249,11761,4943],{"class":1002},[249,11763,4915],{"class":1173},[249,11765,4948],{"class":1002},[249,11767,4951],{"class":1751},[249,11769,1091],{"class":1002},[249,11771,4957],{"class":4956},[249,11773,4960],{"class":1002},[249,11775,11776,11778,11780],{"class":251,"line":277},[249,11777,4965],{"class":1002},[249,11779,4968],{"class":1173},[249,11781,4971],{"class":1002},[249,11783,11784,11786],{"class":251,"line":283},[249,11785,4976],{"class":1173},[249,11787,4971],{"class":1002},[249,11789,11790],{"class":251,"line":288},[249,11791,4765],{"class":1173},[10,11793,4985],{},[10,11795,4988],{},[38,11797,11798,11808],{},[41,11799,11800],{},[44,11801,11802,11804,11806],{},[47,11803,4997],{},[47,11805,5000],{},[47,11807,5003],{},[57,11809,11810,11824,11840,11852],{},[44,11811,11812,11814,11820],{},[62,11813,5010],{},[62,11815,11816,2561,11818],{},[172,11817,5015],{},[172,11819,5018],{},[62,11821,5021,11822],{},[172,11823,5024],{},[44,11825,11826,11828,11834],{},[62,11827,5029],{},[62,11829,11830,2561,11832],{},[172,11831,5034],{},[172,11833,5037],{},[62,11835,11836,2561,11838],{},[172,11837,5042],{},[172,11839,5045],{},[44,11841,11842,11844,11848],{},[62,11843,5050],{},[62,11845,5053,11846],{},[172,11847,5037],{},[62,11849,11850],{},[172,11851,4910],{},[44,11853,11854,11856,11860],{},[62,11855,5064],{},[62,11857,5067,11858],{},[172,11859,5070],{},[62,11861,5073,11862],{},[172,11863,5070],{},[404,11865,5078],{"id":5078},[10,11867,5081],{},[164,11869,11870],{"className":4665,"code":5084,"language":4667,"meta":170,"style":170},[172,11871,11872],{"__ignoreMap":170},[249,11873,11874,11876,11878,11880,11882,11884,11886,11888],{"class":251,"line":252},[249,11875,5091],{"class":995},[249,11877,4754],{"class":1173},[249,11879,5096],{"class":4896},[249,11881,5099],{"class":1085},[249,11883,5102],{"class":1173},[249,11885,5105],{"class":1002},[249,11887,3246],{"class":1772},[249,11889,4765],{"class":1173},[10,11891,5112],{},[404,11893,5115],{"id":5115},[10,11895,5118,11896,5122,11898,5126],{},[172,11897,5121],{},[172,11899,5125],{},[164,11901,11902],{"className":4665,"code":5129,"language":4667,"meta":170,"style":170},[172,11903,11904,11914,11934,11938,11942,11960,11974,11984,11988,11992,12018],{"__ignoreMap":170},[249,11905,11906,11908,11910,11912],{"class":251,"line":252},[249,11907,5136],{"class":1085},[249,11909,5139],{"class":925},[249,11911,5142],{"class":1002},[249,11913,1094],{"class":1002},[249,11915,11916,11918,11920,11922,11924,11926,11928,11930,11932],{"class":251,"line":258},[249,11917,5149],{"class":1751},[249,11919,1091],{"class":1002},[249,11921,4777],{"class":1002},[249,11923,5156],{"class":4896},[249,11925,1091],{"class":1002},[249,11927,5161],{"class":925},[249,11929,5164],{"class":1002},[249,11931,5099],{"class":1085},[249,11933,5169],{"class":925},[249,11935,11936],{"class":251,"line":265},[249,11937,1124],{"class":1002},[249,11939,11940],{"class":251,"line":271},[249,11941,262],{"emptyLinePlaceholder":261},[249,11943,11944,11946,11948,11950,11952,11954,11956,11958],{"class":251,"line":277},[249,11945,5182],{"class":1085},[249,11947,5185],{"class":995},[249,11949,5188],{"class":1002},[249,11951,5191],{"class":4896},[249,11953,5194],{"class":1002},[249,11955,5139],{"class":925},[249,11957,5164],{"class":1002},[249,11959,1094],{"class":1002},[249,11961,11962,11964,11966,11968,11970,11972],{"class":251,"line":283},[249,11963,5205],{"class":1085},[249,11965,5208],{"class":1173},[249,11967,5142],{"class":1002},[249,11969,5213],{"class":1002},[249,11971,5099],{"class":1085},[249,11973,1094],{"class":1002},[249,11975,11976,11978,11980,11982],{"class":251,"line":288},[249,11977,5222],{"class":995},[249,11979,4754],{"class":1751},[249,11981,102],{"class":1772},[249,11983,4765],{"class":1751},[249,11985,11986],{"class":251,"line":294},[249,11987,1119],{"class":1002},[249,11989,11990],{"class":251,"line":300},[249,11991,262],{"emptyLinePlaceholder":261},[249,11993,11994,11996,11998,12000,12002,12004,12006,12008,12010,12012,12014,12016],{"class":251,"line":306},[249,11995,5241],{"class":4674},[249,11997,2984],{"class":1002},[249,11999,4546],{"class":1751},[249,12001,4549],{"class":1085},[249,12003,1177],{"class":1002},[249,12005,1088],{"class":1002},[249,12007,5254],{"class":929},[249,12009,1088],{"class":1002},[249,12011,5191],{"class":1085},[249,12013,5261],{"class":1002},[249,12015,5264],{"class":1173},[249,12017,5267],{"class":1002},[249,12019,12020],{"class":251,"line":311},[249,12021,1124],{"class":1002},[10,12023,5274],{},[404,12025,5277],{"id":5277},[10,12027,5280],{},[10,12029,5283],{},[28,12031,4513],{"id":5286},[404,12033,12034,3924,12036],{"id":5289},[172,12035,5292],{},[172,12037,4043],{},[10,12039,12040,5299,12042,5303,12044,5306],{},[172,12041,5292],{},[172,12043,5302],{},[172,12045,4043],{},[164,12047,12048],{"className":5309,"code":5310,"language":5286,"meta":170,"style":170},[172,12049,12050,12074,12078,12090,12108],{"__ignoreMap":170},[249,12051,12052,12054,12056,12058,12060,12062,12064,12066,12068,12070,12072],{"class":251,"line":252},[249,12053,4738],{"class":1085},[249,12055,4741],{"class":1173},[249,12057,1177],{"class":1002},[249,12059,4746],{"class":1173},[249,12061,1846],{"class":1002},[249,12063,4751],{"class":995},[249,12065,4754],{"class":1173},[249,12067,4757],{"class":1002},[249,12069,4760],{"class":929},[249,12071,4757],{"class":1002},[249,12073,4765],{"class":1173},[249,12075,12076],{"class":251,"line":258},[249,12077,262],{"emptyLinePlaceholder":261},[249,12079,12080,12082,12084,12086,12088],{"class":251,"line":265},[249,12081,4774],{"class":4674},[249,12083,4777],{"class":1173},[249,12085,4780],{"class":1002},[249,12087,4783],{"class":1173},[249,12089,1077],{"class":1002},[249,12091,12092,12094,12096,12098,12100,12102,12104,12106],{"class":251,"line":271},[249,12093,4790],{"class":4674},[249,12095,4793],{"class":1002},[249,12097,4796],{"class":995},[249,12099,4754],{"class":1751},[249,12101,4757],{"class":1002},[249,12103,4803],{"class":929},[249,12105,4757],{"class":1002},[249,12107,4765],{"class":1751},[249,12109,12110],{"class":251,"line":277},[249,12111,1124],{"class":1002},[10,12113,5377,12114,5380],{},[172,12115,4780],{},[404,12117,12118],{"id":5383},[172,12119,5383],{},[10,12121,5388,12122,5391],{},[172,12123,5383],{},[164,12125,12126],{"className":5309,"code":5394,"language":5286,"meta":170,"style":170},[172,12127,12128,12138,12148,12156],{"__ignoreMap":170},[249,12129,12130,12132,12134,12136],{"class":251,"line":252},[249,12131,5136],{"class":1085},[249,12133,5403],{"class":925},[249,12135,5142],{"class":1002},[249,12137,1094],{"class":1002},[249,12139,12140,12142,12144,12146],{"class":251,"line":258},[249,12141,5412],{"class":1085},[249,12143,5415],{"class":1751},[249,12145,1091],{"class":1002},[249,12147,5420],{"class":925},[249,12149,12150,12152,12154],{"class":251,"line":265},[249,12151,5425],{"class":1751},[249,12153,1091],{"class":1002},[249,12155,5430],{"class":925},[249,12157,12158],{"class":251,"line":271},[249,12159,1124],{"class":1002},[10,12161,12162,5439],{},[172,12163,5383],{},[404,12165,5442],{"id":5442},[10,12167,5445],{},[164,12169,12170],{"className":4665,"code":5448,"language":4667,"meta":170,"style":170},[172,12171,12172,12198,12220],{"__ignoreMap":170},[249,12173,12174,12176,12178,12180,12182,12184,12186,12188,12190,12192,12194,12196],{"class":251,"line":252},[249,12175,5182],{"class":1085},[249,12177,5208],{"class":995},[249,12179,4754],{"class":1002},[249,12181,5461],{"class":4896},[249,12183,1091],{"class":1002},[249,12185,5466],{"class":925},[249,12187,1846],{"class":1002},[249,12189,5471],{"class":925},[249,12191,4543],{"class":1002},[249,12193,5476],{"class":925},[249,12195,5479],{"class":1002},[249,12197,1094],{"class":1002},[249,12199,12200,12202,12204,12206,12208,12210,12212,12214,12216,12218],{"class":251,"line":258},[249,12201,5486],{"class":1173},[249,12203,1846],{"class":1002},[249,12205,5491],{"class":995},[249,12207,4754],{"class":1751},[249,12209,5461],{"class":1173},[249,12211,1846],{"class":1002},[249,12213,5500],{"class":1173},[249,12215,1846],{"class":1002},[249,12217,5505],{"class":1173},[249,12219,4765],{"class":1751},[249,12221,12222],{"class":251,"line":265},[249,12223,1124],{"class":1002},[10,12225,5514,12226,5518],{},[172,12227,5517],{},[404,12229,5521],{"id":5521},[10,12231,5524,12232,5528],{},[172,12233,5527],{},[164,12235,12236],{"className":5309,"code":5531,"language":5286,"meta":170,"style":170},[172,12237,12238,12248,12256,12260,12264,12300,12328],{"__ignoreMap":170},[249,12239,12240,12242,12244,12246],{"class":251,"line":252},[249,12241,5136],{"class":1085},[249,12243,5540],{"class":925},[249,12245,5142],{"class":1002},[249,12247,1094],{"class":1002},[249,12249,12250,12252,12254],{"class":251,"line":258},[249,12251,5549],{"class":1751},[249,12253,1091],{"class":1002},[249,12255,5420],{"class":925},[249,12257,12258],{"class":251,"line":265},[249,12259,1124],{"class":1002},[249,12261,12262],{"class":251,"line":271},[249,12263,262],{"emptyLinePlaceholder":261},[249,12265,12266,12268,12270,12272,12274,12276,12278,12280,12282,12284,12286,12288,12290,12292,12294,12296,12298],{"class":251,"line":277},[249,12267,5182],{"class":1085},[249,12269,5568],{"class":995},[249,12271,4543],{"class":1002},[249,12273,5573],{"class":925},[249,12275,5576],{"class":1085},[249,12277,5540],{"class":925},[249,12279,5581],{"class":1002},[249,12281,5584],{"class":4896},[249,12283,1091],{"class":1002},[249,12285,5589],{"class":925},[249,12287,5592],{"class":1173},[249,12289,4948],{"class":1002},[249,12291,5415],{"class":4896},[249,12293,1091],{"class":1002},[249,12295,5161],{"class":925},[249,12297,5164],{"class":1002},[249,12299,1094],{"class":1002},[249,12301,12302,12304,12306,12308,12310,12312,12314,12316,12318,12320,12322,12324,12326],{"class":251,"line":283},[249,12303,5241],{"class":4674},[249,12305,5611],{"class":1173},[249,12307,1846],{"class":1002},[249,12309,5616],{"class":995},[249,12311,4754],{"class":1751},[249,12313,5621],{"class":4896},[249,12315,5099],{"class":1085},[249,12317,5626],{"class":1173},[249,12319,1846],{"class":1002},[249,12321,5156],{"class":1173},[249,12323,5633],{"class":1002},[249,12325,5415],{"class":1173},[249,12327,4765],{"class":1751},[249,12329,12330],{"class":251,"line":288},[249,12331,1124],{"class":1002},[10,12333,5644,12334,5647,12336,5650],{},[172,12335,5573],{},[172,12337,5156],{},[404,12339,12340,5657],{"id":5653},[172,12341,5656],{},[10,12343,12344,5662],{},[172,12345,5656],{},[164,12347,12348],{"className":5309,"code":5665,"language":5286,"meta":170,"style":170},[172,12349,12350,12360,12368,12376,12380,12384,12396],{"__ignoreMap":170},[249,12351,12352,12354,12356,12358],{"class":251,"line":252},[249,12353,5136],{"class":1085},[249,12355,5403],{"class":925},[249,12357,5142],{"class":1002},[249,12359,1094],{"class":1002},[249,12361,12362,12364,12366],{"class":251,"line":258},[249,12363,5549],{"class":1751},[249,12365,1091],{"class":1002},[249,12367,5420],{"class":925},[249,12369,12370,12372,12374],{"class":251,"line":265},[249,12371,5425],{"class":1751},[249,12373,1091],{"class":1002},[249,12375,5430],{"class":925},[249,12377,12378],{"class":251,"line":271},[249,12379,1124],{"class":1002},[249,12381,12382],{"class":251,"line":277},[249,12383,262],{"emptyLinePlaceholder":261},[249,12385,12386,12388,12390,12392,12394],{"class":251,"line":283},[249,12387,5136],{"class":1085},[249,12389,5708],{"class":925},[249,12391,5142],{"class":1002},[249,12393,5713],{"class":1002},[249,12395,5716],{"class":925},[249,12397,12398],{"class":251,"line":288},[249,12399,5721],{"class":2057},[10,12401,5724],{},[404,12403,5727],{"id":5727},[10,12405,5730],{},[164,12407,12408],{"className":5309,"code":5733,"language":5286,"meta":170,"style":170},[172,12409,12410,12420,12428,12436,12440,12444,12464,12468,12472,12490],{"__ignoreMap":170},[249,12411,12412,12414,12416,12418],{"class":251,"line":252},[249,12413,5136],{"class":1085},[249,12415,5403],{"class":925},[249,12417,5142],{"class":1002},[249,12419,1094],{"class":1002},[249,12421,12422,12424,12426],{"class":251,"line":258},[249,12423,5549],{"class":1751},[249,12425,1091],{"class":1002},[249,12427,5420],{"class":925},[249,12429,12430,12432,12434],{"class":251,"line":265},[249,12431,5425],{"class":1751},[249,12433,1091],{"class":1002},[249,12435,5430],{"class":925},[249,12437,12438],{"class":251,"line":271},[249,12439,1124],{"class":1002},[249,12441,12442],{"class":251,"line":277},[249,12443,262],{"emptyLinePlaceholder":261},[249,12445,12446,12448,12450,12452,12454,12456,12458,12460,12462],{"class":251,"line":283},[249,12447,5136],{"class":1085},[249,12449,5776],{"class":925},[249,12451,5142],{"class":1002},[249,12453,5403],{"class":925},[249,12455,5783],{"class":1173},[249,12457,4757],{"class":1002},[249,12459,5156],{"class":929},[249,12461,4757],{"class":1002},[249,12463,4146],{"class":1173},[249,12465,12466],{"class":251,"line":288},[249,12467,5796],{"class":2057},[249,12469,12470],{"class":251,"line":294},[249,12471,262],{"emptyLinePlaceholder":261},[249,12473,12474,12476,12478,12480,12482,12484,12486,12488],{"class":251,"line":300},[249,12475,5136],{"class":1085},[249,12477,5807],{"class":925},[249,12479,5142],{"class":1002},[249,12481,5403],{"class":925},[249,12483,5783],{"class":1173},[249,12485,5656],{"class":1002},[249,12487,5403],{"class":925},[249,12489,4146],{"class":1173},[249,12491,12492],{"class":251,"line":306},[249,12493,5824],{"class":2057},[404,12495,5827],{"id":5827},[10,12497,12498,5833],{},[172,12499,5832],{},[164,12501,12502],{"className":5309,"code":5836,"language":5286,"meta":170,"style":170},[172,12503,12504],{"__ignoreMap":170},[249,12505,12506,12508,12510,12512,12514],{"class":251,"line":252},[249,12507,5832],{"class":1085},[249,12509,5845],{"class":1085},[249,12511,5848],{"class":1173},[249,12513,1091],{"class":1002},[249,12515,5430],{"class":925},[10,12517,5855,12518,5859,12520,5862],{},[172,12519,5858],{},[172,12521,5832],{},[404,12523,5865],{"id":5865},[10,12525,5868],{},[164,12527,12528],{"className":5309,"code":5871,"language":5286,"meta":170,"style":170},[172,12529,12530,12540,12556,12560,12564,12574,12594],{"__ignoreMap":170},[249,12531,12532,12534,12536,12538],{"class":251,"line":252},[249,12533,5136],{"class":1085},[249,12535,5880],{"class":925},[249,12537,5142],{"class":1002},[249,12539,1094],{"class":1002},[249,12541,12542,12544,12546,12548,12550,12552,12554],{"class":251,"line":258},[249,12543,5889],{"class":1751},[249,12545,4754],{"class":1002},[249,12547,5894],{"class":4896},[249,12549,1091],{"class":1002},[249,12551,5899],{"class":925},[249,12553,5902],{"class":1002},[249,12555,5430],{"class":925},[249,12557,12558],{"class":251,"line":265},[249,12559,1124],{"class":1002},[249,12561,12562],{"class":251,"line":271},[249,12563,262],{"emptyLinePlaceholder":261},[249,12565,12566,12568,12570,12572],{"class":251,"line":277},[249,12567,5136],{"class":1085},[249,12569,5919],{"class":925},[249,12571,5142],{"class":1002},[249,12573,1094],{"class":1002},[249,12575,12576,12578,12580,12582,12584,12586,12588,12590,12592],{"class":251,"line":283},[249,12577,5889],{"class":1751},[249,12579,1091],{"class":1002},[249,12581,4777],{"class":1002},[249,12583,5894],{"class":4896},[249,12585,1091],{"class":1002},[249,12587,5899],{"class":925},[249,12589,5164],{"class":1002},[249,12591,5099],{"class":1085},[249,12593,5430],{"class":925},[249,12595,12596],{"class":251,"line":288},[249,12597,1124],{"class":1002},[10,12599,5950,12600,5954],{},[172,12601,5953],{},[404,12603,5957],{"id":5957},[10,12605,5960],{},[164,12607,12608],{"className":5309,"code":5963,"language":5286,"meta":170,"style":170},[172,12609,12610,12634,12650,12654,12658,12672,12676,12688,12710],{"__ignoreMap":170},[249,12611,12612,12614,12616,12618,12620,12622,12624,12626,12628,12630,12632],{"class":251,"line":252},[249,12613,5182],{"class":1085},[249,12615,5972],{"class":995},[249,12617,4754],{"class":1002},[249,12619,5894],{"class":4896},[249,12621,1091],{"class":1002},[249,12623,5981],{"class":925},[249,12625,5902],{"class":1002},[249,12627,5986],{"class":4896},[249,12629,5989],{"class":1002},[249,12631,5161],{"class":925},[249,12633,1094],{"class":1002},[249,12635,12636,12638,12640,12642,12644,12646,12648],{"class":251,"line":258},[249,12637,5241],{"class":4674},[249,12639,6000],{"class":1002},[249,12641,5986],{"class":1173},[249,12643,5633],{"class":1002},[249,12645,1003],{"class":1002},[249,12647,6009],{"class":929},[249,12649,1009],{"class":1002},[249,12651,12652],{"class":251,"line":265},[249,12653,1124],{"class":1002},[249,12655,12656],{"class":251,"line":271},[249,12657,262],{"emptyLinePlaceholder":261},[249,12659,12660,12662,12664,12666,12668,12670],{"class":251,"line":277},[249,12661,4738],{"class":1085},[249,12663,5986],{"class":1173},[249,12665,1091],{"class":1002},[249,12667,5981],{"class":925},[249,12669,5142],{"class":1002},[249,12671,6034],{"class":1772},[249,12673,12674],{"class":251,"line":283},[249,12675,262],{"emptyLinePlaceholder":261},[249,12677,12678,12680,12682,12684,12686],{"class":251,"line":288},[249,12679,4774],{"class":4674},[249,12681,4777],{"class":1173},[249,12683,6047],{"class":995},[249,12685,6050],{"class":1173},[249,12687,1077],{"class":1002},[249,12689,12690,12692,12694,12696,12698,12700,12702,12704,12706,12708],{"class":251,"line":294},[249,12691,5486],{"class":1173},[249,12693,1846],{"class":1002},[249,12695,5491],{"class":995},[249,12697,4754],{"class":1751},[249,12699,5894],{"class":1173},[249,12701,1846],{"class":1002},[249,12703,6069],{"class":995},[249,12705,4754],{"class":1751},[249,12707,112],{"class":1772},[249,12709,6076],{"class":1751},[249,12711,12712],{"class":251,"line":300},[249,12713,1124],{"class":1002},[10,12715,6083],{},[28,12717,465],{"id":465},[10,12719,6088],{},[10,12721,6091],{},[499,12723,6094],{},{"title":170,"searchDepth":258,"depth":258,"links":12725},[12726,12729,12733,12740,12751],{"id":4516,"depth":258,"text":4505,"children":12727},[12728],{"id":4519,"depth":265,"text":4519},{"id":3799,"depth":258,"text":4482,"children":12730},[12731,12732],{"id":4576,"depth":265,"text":4576},{"id":4627,"depth":265,"text":4628},{"id":4647,"depth":258,"text":4510,"children":12734},[12735,12736,12737,12738,12739],{"id":4650,"depth":265,"text":4653},{"id":4878,"depth":265,"text":4878},{"id":5078,"depth":265,"text":5078},{"id":5115,"depth":265,"text":5115},{"id":5277,"depth":265,"text":5277},{"id":5286,"depth":258,"text":4513,"children":12741},[12742,12743,12744,12745,12746,12747,12748,12749,12750],{"id":5289,"depth":265,"text":6114},{"id":5383,"depth":265,"text":5383},{"id":5442,"depth":265,"text":5442},{"id":5521,"depth":265,"text":5521},{"id":5653,"depth":265,"text":5653},{"id":5727,"depth":265,"text":5727},{"id":5827,"depth":265,"text":5827},{"id":5865,"depth":265,"text":5865},{"id":5957,"depth":265,"text":5957},{"id":465,"depth":258,"text":465},{},{"title":4487,"description":6124},[4510,4513],{"id":6134,"title":6135,"body":12756,"description":6611,"extension":517,"meta":13130,"navigation":261,"path":6613,"publishDate":6614,"published":261,"seo":13131,"stem":6616,"tags":13132,"thumbnail":6619,"updated":6614,"__hash__":6620},{"type":7,"value":12757,"toc":13120},[12758,12760,12762,12768,12770,12772,12774,12776,12842,12844,12848,12850,12874,12880,12924,12926,12928,12934,12950,12952,12954,12956,12958,12960,13044,13046,13056,13058,13060,13062,13082,13086,13088,13090,13094,13096,13098,13110,13112,13114,13116,13118],[10,12759,12],{},[10,12761,6142],{},[10,12763,6145,12764,2561,12766,6152],{},[172,12765,6148],{},[172,12767,6151],{},[28,12769,6155],{"id":6155},[10,12771,6158],{},[10,12773,6161],{},[10,12775,6164],{},[38,12777,12778,12790],{},[41,12779,12780],{},[44,12781,12782,12784,12786,12788],{},[47,12783,834],{},[47,12785,6148],{},[47,12787,6151],{},[47,12789,6179],{},[57,12791,12792,12802,12812,12822,12832],{},[44,12793,12794,12796,12798,12800],{},[62,12795,6186],{},[62,12797,6189],{},[62,12799,6189],{},[62,12801,6194],{},[44,12803,12804,12806,12808,12810],{},[62,12805,64],{},[62,12807,6201],{},[62,12809,6201],{},[62,12811,6206],{},[44,12813,12814,12816,12818,12820],{},[62,12815,6211],{},[62,12817,6214],{},[62,12819,6217],{},[62,12821,6214],{},[44,12823,12824,12826,12828,12830],{},[62,12825,6224],{},[62,12827,6227],{},[62,12829,6230],{},[62,12831,6227],{},[44,12833,12834,12836,12838,12840],{},[62,12835,6237],{},[62,12837,6240],{},[62,12839,6243],{},[62,12841,6246],{},[28,12843,6148],{"id":6249},[10,12845,12846,6254],{},[172,12847,6148],{},[10,12849,6257],{},[164,12851,12852],{"className":3797,"code":6260,"language":3799,"meta":170,"style":170},[172,12853,12854,12858,12862,12866,12870],{"__ignoreMap":170},[249,12855,12856],{"class":251,"line":252},[249,12857,6267],{},[249,12859,12860],{"class":251,"line":258},[249,12861,262],{"emptyLinePlaceholder":261},[249,12863,12864],{"class":251,"line":265},[249,12865,6276],{},[249,12867,12868],{"class":251,"line":271},[249,12869,262],{"emptyLinePlaceholder":261},[249,12871,12872],{"class":251,"line":277},[249,12873,6285],{},[10,12875,6288,12876,6292,12878,6296],{},[172,12877,6291],{},[172,12879,6295],{},[164,12881,12882],{"className":3797,"code":6299,"language":3799,"meta":170,"style":170},[172,12883,12884,12888,12892,12896,12900,12904,12908,12912,12916,12920],{"__ignoreMap":170},[249,12885,12886],{"class":251,"line":252},[249,12887,6306],{},[249,12889,12890],{"class":251,"line":258},[249,12891,6311],{},[249,12893,12894],{"class":251,"line":265},[249,12895,6316],{},[249,12897,12898],{"class":251,"line":271},[249,12899,1124],{},[249,12901,12902],{"class":251,"line":277},[249,12903,262],{"emptyLinePlaceholder":261},[249,12905,12906],{"class":251,"line":283},[249,12907,6329],{},[249,12909,12910],{"class":251,"line":288},[249,12911,262],{"emptyLinePlaceholder":261},[249,12913,12914],{"class":251,"line":294},[249,12915,6338],{},[249,12917,12918],{"class":251,"line":300},[249,12919,6343],{},[249,12921,12922],{"class":251,"line":306},[249,12923,4765],{},[10,12925,6350],{},[28,12927,6151],{"id":6353},[10,12929,12930,6358,12932,6361],{},[172,12931,6151],{},[172,12933,6148],{},[164,12935,12936],{"className":3797,"code":6364,"language":3799,"meta":170,"style":170},[172,12937,12938,12942,12946],{"__ignoreMap":170},[249,12939,12940],{"class":251,"line":252},[249,12941,6371],{},[249,12943,12944],{"class":251,"line":258},[249,12945,262],{"emptyLinePlaceholder":261},[249,12947,12948],{"class":251,"line":265},[249,12949,6380],{},[10,12951,6383],{},[10,12953,6386],{},[28,12955,6179],{"id":6389},[10,12957,6392],{},[10,12959,6395],{},[164,12961,12962],{"className":3797,"code":6398,"language":3799,"meta":170,"style":170},[172,12963,12964,12968,12972,12976,12980,12984,12988,12992,12996,13000,13004,13008,13012,13016,13020,13024,13028,13032,13036,13040],{"__ignoreMap":170},[249,12965,12966],{"class":251,"line":252},[249,12967,6405],{},[249,12969,12970],{"class":251,"line":258},[249,12971,262],{"emptyLinePlaceholder":261},[249,12973,12974],{"class":251,"line":265},[249,12975,6414],{},[249,12977,12978],{"class":251,"line":271},[249,12979,6419],{},[249,12981,12982],{"class":251,"line":277},[249,12983,262],{"emptyLinePlaceholder":261},[249,12985,12986],{"class":251,"line":283},[249,12987,6428],{},[249,12989,12990],{"class":251,"line":288},[249,12991,6433],{},[249,12993,12994],{"class":251,"line":294},[249,12995,6438],{},[249,12997,12998],{"class":251,"line":300},[249,12999,6443],{},[249,13001,13002],{"class":251,"line":306},[249,13003,6448],{},[249,13005,13006],{"class":251,"line":311},[249,13007,1119],{},[249,13009,13010],{"class":251,"line":317},[249,13011,1124],{},[249,13013,13014],{"class":251,"line":323},[249,13015,262],{"emptyLinePlaceholder":261},[249,13017,13018],{"class":251,"line":329},[249,13019,6465],{},[249,13021,13022],{"class":251,"line":334},[249,13023,6419],{},[249,13025,13026],{"class":251,"line":6472},[249,13027,6475],{},[249,13029,13030],{"class":251,"line":6478},[249,13031,6481],{},[249,13033,13034],{"class":251,"line":6484},[249,13035,262],{"emptyLinePlaceholder":261},[249,13037,13038],{"class":251,"line":6489},[249,13039,6492],{},[249,13041,13042],{"class":251,"line":6495},[249,13043,1124],{},[10,13045,6500],{},[470,13047,13048,13050,13052,13054],{},[473,13049,6505],{},[473,13051,6508],{},[473,13053,6511],{},[473,13055,6514],{},[28,13057,6517],{"id":6517},[10,13059,6520],{},[10,13061,6523],{},[164,13063,13064],{"className":3797,"code":6526,"language":3799,"meta":170,"style":170},[172,13065,13066,13070,13074,13078],{"__ignoreMap":170},[249,13067,13068],{"class":251,"line":252},[249,13069,6533],{},[249,13071,13072],{"class":251,"line":258},[249,13073,262],{"emptyLinePlaceholder":261},[249,13075,13076],{"class":251,"line":265},[249,13077,6542],{},[249,13079,13080],{"class":251,"line":271},[249,13081,6547],{},[2117,13083,13084],{"title":6550,"type":2367},[10,13085,6553],{},[28,13087,6556],{"id":6556},[10,13089,6559],{},[2117,13091,13092],{"title":6562,"type":6563},[10,13093,6566],{},[28,13095,6569],{"id":6569},[10,13097,6572],{},[470,13099,13100,13104,13108],{},[473,13101,6577,13102],{},[172,13103,6148],{},[473,13105,6582,13106],{},[172,13107,6151],{},[473,13109,6587],{},[10,13111,6590],{},[28,13113,465],{"id":465},[10,13115,6595],{},[10,13117,6598],{},[499,13119,501],{},{"title":170,"searchDepth":258,"depth":258,"links":13121},[13122,13123,13124,13125,13126,13127,13128,13129],{"id":6155,"depth":258,"text":6155},{"id":6249,"depth":258,"text":6148},{"id":6353,"depth":258,"text":6151},{"id":6389,"depth":258,"text":6179},{"id":6517,"depth":258,"text":6517},{"id":6556,"depth":258,"text":6556},{"id":6569,"depth":258,"text":6569},{"id":465,"depth":258,"text":465},{},{"title":6135,"description":6611},[6618,6179],{"id":6622,"title":6623,"body":13134,"description":7099,"extension":517,"meta":13501,"navigation":261,"path":7101,"publishDate":7102,"published":261,"seo":13502,"stem":7104,"tags":13503,"thumbnail":7106,"updated":7102,"__hash__":7107},{"type":7,"value":13135,"toc":13491},[13136,13138,13143,13145,13147,13149,13151,13153,13165,13167,13169,13171,13227,13229,13255,13257,13259,13261,13263,13273,13275,13311,13313,13315,13317,13319,13329,13333,13335,13337,13339,13357,13359,13361,13363,13365,13367,13379,13381,13383,13447,13449,13454,13460,13466,13468,13482,13484,13489],[10,13137,12],{},[10,13139,6630,13140,6636],{},[151,13141,6635],{"href":6633,"rel":13142},[155],[10,13144,6639],{},[28,13146,6643],{"id":6642},[10,13148,6646],{},[10,13150,6649],{},[10,13152,6652],{},[470,13154,13155,13157,13159,13161,13163],{},[473,13156,6657],{},[473,13158,6660],{},[473,13160,6663],{},[473,13162,6666],{},[473,13164,6669],{},[28,13166,6657],{"id":6657},[10,13168,6674],{},[10,13170,6677],{},[164,13172,13173],{"className":3797,"code":6680,"language":3799,"meta":170,"style":170},[172,13174,13175,13179,13183,13187,13191,13195,13199,13203,13207,13211,13215,13219,13223],{"__ignoreMap":170},[249,13176,13177],{"class":251,"line":252},[249,13178,6687],{},[249,13180,13181],{"class":251,"line":258},[249,13182,6692],{},[249,13184,13185],{"class":251,"line":265},[249,13186,1124],{},[249,13188,13189],{"class":251,"line":271},[249,13190,262],{"emptyLinePlaceholder":261},[249,13192,13193],{"class":251,"line":277},[249,13194,6705],{},[249,13196,13197],{"class":251,"line":283},[249,13198,6710],{},[249,13200,13201],{"class":251,"line":288},[249,13202,1124],{},[249,13204,13205],{"class":251,"line":294},[249,13206,262],{"emptyLinePlaceholder":261},[249,13208,13209],{"class":251,"line":300},[249,13210,6723],{},[249,13212,13213],{"class":251,"line":306},[249,13214,6728],{},[249,13216,13217],{"class":251,"line":311},[249,13218,1124],{},[249,13220,13221],{"class":251,"line":317},[249,13222,262],{"emptyLinePlaceholder":261},[249,13224,13225],{"class":251,"line":323},[249,13226,6741],{},[10,13228,6744],{},[638,13230,13231,13235,13241,13247],{},[473,13232,13233,6752],{},[172,13234,6751],{},[473,13236,13237,6757,13239,6761],{},[172,13238,6751],{},[172,13240,6760],{},[473,13242,13243,6757,13245,6761],{},[172,13244,6760],{},[172,13246,6768],{},[473,13248,13249,2561,13251,2561,13253,6777],{},[172,13250,6768],{},[172,13252,6760],{},[172,13254,6751],{},[10,13256,6780],{},[28,13258,6660],{"id":6783},[10,13260,6786],{},[10,13262,6789],{},[470,13264,13265,13267,13269,13271],{},[473,13266,6794],{},[473,13268,6797],{},[473,13270,6800],{},[473,13272,6803],{},[10,13274,6806],{},[164,13276,13277],{"className":3797,"code":6809,"language":3799,"meta":170,"style":170},[172,13278,13279,13283,13287,13291,13295,13299,13303,13307],{"__ignoreMap":170},[249,13280,13281],{"class":251,"line":252},[249,13282,6816],{},[249,13284,13285],{"class":251,"line":258},[249,13286,6821],{},[249,13288,13289],{"class":251,"line":265},[249,13290,6826],{},[249,13292,13293],{"class":251,"line":271},[249,13294,4765],{},[249,13296,13297],{"class":251,"line":277},[249,13298,262],{"emptyLinePlaceholder":261},[249,13300,13301],{"class":251,"line":283},[249,13302,6839],{},[249,13304,13305],{"class":251,"line":288},[249,13306,6844],{},[249,13308,13309],{"class":251,"line":294},[249,13310,6849],{},[10,13312,6852],{},[28,13314,6663],{"id":6663},[10,13316,6857],{},[10,13318,6860],{},[470,13320,13321,13325,13327],{},[473,13322,13323,6868],{},[172,13324,6867],{},[473,13326,6871],{},[473,13328,6874],{},[10,13330,13331,6879],{},[172,13332,6867],{},[10,13334,6882],{},[28,13336,6666],{"id":6666},[10,13338,6887],{},[470,13340,13341,13349,13353],{},[473,13342,6892,13343,2561,13345,2561,13347],{},[172,13344,6895],{},[172,13346,6898],{},[172,13348,6901],{},[473,13350,13351,6907],{},[172,13352,6906],{},[473,13354,13355,6868],{},[172,13356,6912],{},[10,13358,6915],{},[10,13360,6918],{},[28,13362,6669],{"id":6669},[10,13364,6923],{},[10,13366,6926],{},[638,13368,13369,13371,13373,13375,13377],{},[473,13370,6931],{},[473,13372,6934],{},[473,13374,6937],{},[473,13376,6940],{},[473,13378,6943],{},[28,13380,6946],{"id":6946},[10,13382,6949],{},[164,13384,13385],{"className":3797,"code":6952,"language":3799,"meta":170,"style":170},[172,13386,13387,13391,13395,13399,13403,13407,13411,13415,13419,13423,13427,13431,13435,13439,13443],{"__ignoreMap":170},[249,13388,13389],{"class":251,"line":252},[249,13390,6959],{},[249,13392,13393],{"class":251,"line":258},[249,13394,262],{"emptyLinePlaceholder":261},[249,13396,13397],{"class":251,"line":265},[249,13398,6968],{},[249,13400,13401],{"class":251,"line":271},[249,13402,6973],{},[249,13404,13405],{"class":251,"line":277},[249,13406,6978],{},[249,13408,13409],{"class":251,"line":283},[249,13410,262],{"emptyLinePlaceholder":261},[249,13412,13413],{"class":251,"line":288},[249,13414,6987],{},[249,13416,13417],{"class":251,"line":294},[249,13418,6992],{},[249,13420,13421],{"class":251,"line":300},[249,13422,6997],{},[249,13424,13425],{"class":251,"line":306},[249,13426,262],{"emptyLinePlaceholder":261},[249,13428,13429],{"class":251,"line":311},[249,13430,7006],{},[249,13432,13433],{"class":251,"line":317},[249,13434,7011],{},[249,13436,13437],{"class":251,"line":323},[249,13438,6997],{},[249,13440,13441],{"class":251,"line":329},[249,13442,262],{"emptyLinePlaceholder":261},[249,13444,13445],{"class":251,"line":334},[249,13446,7024],{},[10,13448,7027],{},[164,13450,13452],{"className":13451,"code":7031,"language":169,"meta":170},[167],[172,13453,7031],{"__ignoreMap":170},[10,13455,7036,13456,2557,13458,7043],{},[172,13457,7039],{},[172,13459,7042],{},[10,13461,7046,13462,7049,13464,7052],{},[172,13463,6906],{},[172,13465,6867],{},[28,13467,465],{"id":465},[470,13469,13470,13472,13474,13476,13478,13480],{},[473,13471,7059],{},[473,13473,7062],{},[473,13475,7065],{},[473,13477,7068],{},[473,13479,7071],{},[473,13481,7074],{},[10,13483,7077],{},[10,13485,7080,13486,7086],{},[151,13487,7085],{"href":7083,"rel":13488},[155],[499,13490,501],{},{"title":170,"searchDepth":258,"depth":258,"links":13492},[13493,13494,13495,13496,13497,13498,13499,13500],{"id":6642,"depth":258,"text":6643},{"id":6657,"depth":258,"text":6657},{"id":6783,"depth":258,"text":6660},{"id":6663,"depth":258,"text":6663},{"id":6666,"depth":258,"text":6666},{"id":6669,"depth":258,"text":6669},{"id":6946,"depth":258,"text":6946},{"id":465,"depth":258,"text":465},{},{"title":6623,"description":7099},[4482],{"id":7109,"title":7110,"body":13505,"description":7526,"extension":517,"meta":13827,"navigation":261,"path":7528,"publishDate":7529,"published":261,"seo":13828,"stem":7531,"tags":13829,"thumbnail":7533,"updated":7529,"__hash__":7534},{"type":7,"value":13506,"toc":13819},[13507,13509,13511,13513,13515,13517,13525,13530,13532,13538,13562,13572,13577,13579,13583,13619,13625,13631,13639,13659,13661,13665,13701,13705,13709,13729,13731,13737,13773,13779,13791,13793,13815,13817],[10,13508,12],{},[10,13510,7117],{},[10,13512,7120],{},[28,13514,7124],{"id":7123},[10,13516,7127],{},[10,13518,13519,2561,13521,2561,13523,7139],{},[172,13520,7132],{},[172,13522,7135],{},[172,13524,7138],{},[10,13526,7142,13527,7148],{},[151,13528,7147],{"href":7145,"rel":13529},[155],[28,13531,7152],{"id":7151},[10,13533,7155,13534,7158,13536,7162],{},[172,13535,2305],{},[172,13537,7161],{},[164,13539,13540],{"className":3797,"code":7165,"language":3799,"meta":170,"style":170},[172,13541,13542,13546,13550,13554,13558],{"__ignoreMap":170},[249,13543,13544],{"class":251,"line":252},[249,13545,7172],{},[249,13547,13548],{"class":251,"line":258},[249,13549,3998],{},[249,13551,13552],{"class":251,"line":265},[249,13553,1124],{},[249,13555,13556],{"class":251,"line":271},[249,13557,262],{"emptyLinePlaceholder":261},[249,13559,13560],{"class":251,"line":277},[249,13561,7189],{},[10,13563,7192,13564,7196,13566,7200,13568,7203,13570,7206],{},[172,13565,7195],{},[172,13567,7199],{},[172,13569,7199],{},[172,13571,7161],{},[10,13573,7209,13574,7086],{},[151,13575,7214],{"href":7212,"rel":13576},[155],[28,13578,7217],{"id":7217},[10,13580,7220,13581,7224],{},[172,13582,7223],{},[164,13584,13585],{"className":3797,"code":7227,"language":3799,"meta":170,"style":170},[172,13586,13587,13591,13595,13599,13603,13607,13611,13615],{"__ignoreMap":170},[249,13588,13589],{"class":251,"line":252},[249,13590,7172],{},[249,13592,13593],{"class":251,"line":258},[249,13594,3998],{},[249,13596,13597],{"class":251,"line":265},[249,13598,7242],{},[249,13600,13601],{"class":251,"line":271},[249,13602,7247],{},[249,13604,13605],{"class":251,"line":277},[249,13606,3877],{},[249,13608,13609],{"class":251,"line":283},[249,13610,1124],{},[249,13612,13613],{"class":251,"line":288},[249,13614,262],{"emptyLinePlaceholder":261},[249,13616,13617],{"class":251,"line":294},[249,13618,7264],{},[10,13620,7267,13621,7271,13623,7275],{},[172,13622,7270],{},[172,13624,7274],{},[10,13626,13627,7280,13629,7283],{},[172,13628,7195],{},[172,13630,7223],{},[10,13632,357,13633,7289,13635,7292,13637,7295],{},[172,13634,7288],{},[172,13636,7199],{},[172,13638,7161],{},[164,13640,13641],{"className":3797,"code":7298,"language":3799,"meta":170,"style":170},[172,13642,13643,13647,13651,13655],{"__ignoreMap":170},[249,13644,13645],{"class":251,"line":252},[249,13646,7305],{},[249,13648,13649],{"class":251,"line":258},[249,13650,7310],{},[249,13652,13653],{"class":251,"line":265},[249,13654,262],{"emptyLinePlaceholder":261},[249,13656,13657],{"class":251,"line":271},[249,13658,7319],{},[28,13660,7323],{"id":7322},[10,13662,7326,13663,7330],{},[172,13664,7329],{},[164,13666,13667],{"className":3797,"code":7333,"language":3799,"meta":170,"style":170},[172,13668,13669,13673,13677,13681,13685,13689,13693,13697],{"__ignoreMap":170},[249,13670,13671],{"class":251,"line":252},[249,13672,7172],{},[249,13674,13675],{"class":251,"line":258},[249,13676,3998],{},[249,13678,13679],{"class":251,"line":265},[249,13680,7242],{},[249,13682,13683],{"class":251,"line":271},[249,13684,7247],{},[249,13686,13687],{"class":251,"line":277},[249,13688,3877],{},[249,13690,13691],{"class":251,"line":283},[249,13692,1124],{},[249,13694,13695],{"class":251,"line":288},[249,13696,262],{"emptyLinePlaceholder":261},[249,13698,13699],{"class":251,"line":294},[249,13700,7368],{},[10,13702,7371,13703,7374],{},[172,13704,7223],{},[10,13706,13707,7379],{},[172,13708,7288],{},[164,13710,13711],{"className":3797,"code":7382,"language":3799,"meta":170,"style":170},[172,13712,13713,13717,13721,13725],{"__ignoreMap":170},[249,13714,13715],{"class":251,"line":252},[249,13716,7305],{},[249,13718,13719],{"class":251,"line":258},[249,13720,7310],{},[249,13722,13723],{"class":251,"line":265},[249,13724,262],{"emptyLinePlaceholder":261},[249,13726,13727],{"class":251,"line":271},[249,13728,7368],{},[28,13730,7403],{"id":7403},[10,13732,13733,7408,13735,7412],{},[172,13734,7329],{},[172,13736,7411],{},[164,13738,13739],{"className":3797,"code":7415,"language":3799,"meta":170,"style":170},[172,13740,13741,13745,13749,13753,13757,13761,13765,13769],{"__ignoreMap":170},[249,13742,13743],{"class":251,"line":252},[249,13744,7172],{},[249,13746,13747],{"class":251,"line":258},[249,13748,3998],{},[249,13750,13751],{"class":251,"line":265},[249,13752,7242],{},[249,13754,13755],{"class":251,"line":271},[249,13756,7247],{},[249,13758,13759],{"class":251,"line":277},[249,13760,3877],{},[249,13762,13763],{"class":251,"line":283},[249,13764,1124],{},[249,13766,13767],{"class":251,"line":288},[249,13768,262],{"emptyLinePlaceholder":261},[249,13770,13771],{"class":251,"line":294},[249,13772,7450],{},[10,13774,13775,7456,13777,7460],{},[172,13776,7455],{},[172,13778,7459],{},[10,13780,7463,13781,7466,13783,7469,13785,7472,13787,7475,13789,7478],{},[172,13782,7199],{},[172,13784,7161],{},[172,13786,7195],{},[172,13788,7459],{},[172,13790,7195],{},[28,13792,465],{"id":465},[470,13794,13795,13799,13801,13807,13811],{},[473,13796,7485,13797,7488],{},[172,13798,7199],{},[473,13800,7491],{},[473,13802,13803,7289,13805,7498],{},[172,13804,7288],{},[172,13806,7161],{},[473,13808,7501,13809,7505],{},[172,13810,7504],{},[473,13812,7508,13813,7512],{},[172,13814,7511],{},[10,13816,7515],{},[499,13818,501],{},{"title":170,"searchDepth":258,"depth":258,"links":13820},[13821,13822,13823,13824,13825,13826],{"id":7123,"depth":258,"text":7124},{"id":7151,"depth":258,"text":7152},{"id":7217,"depth":258,"text":7217},{"id":7322,"depth":258,"text":7323},{"id":7403,"depth":258,"text":7403},{"id":465,"depth":258,"text":465},{},{"title":7110,"description":7526},[4482],{"id":7536,"title":7537,"body":13831,"description":7917,"extension":517,"meta":14126,"navigation":261,"path":7919,"publishDate":7920,"published":261,"seo":14127,"stem":7922,"tags":14128,"thumbnail":7924,"updated":7920,"__hash__":7925},{"type":7,"value":13832,"toc":14119},[13833,13835,13837,13839,13841,13843,13845,13850,13852,13856,13900,13908,13920,13922,13942,13944,13952,13954,13958,14002,14006,14018,14020,14040,14050,14054,14059,14061,14063,14071,14073,14091,14095,14097,14115,14117],[10,13834,12],{},[10,13836,7544],{},[10,13838,7547],{},[28,13840,7551],{"id":7550},[10,13842,7554],{},[10,13844,7557],{},[10,13846,7560,13847,7566],{},[151,13848,7565],{"href":7563,"rel":13849},[155],[28,13851,7569],{"id":7569},[10,13853,7572,13854,7576],{},[172,13855,7575],{},[164,13857,13858],{"className":3797,"code":7579,"language":3799,"meta":170,"style":170},[172,13859,13860,13864,13868,13872,13876,13880,13884,13888,13892,13896],{"__ignoreMap":170},[249,13861,13862],{"class":251,"line":252},[249,13863,7586],{},[249,13865,13866],{"class":251,"line":258},[249,13867,7591],{},[249,13869,13870],{"class":251,"line":265},[249,13871,7596],{},[249,13873,13874],{"class":251,"line":271},[249,13875,3877],{},[249,13877,13878],{"class":251,"line":277},[249,13879,7605],{},[249,13881,13882],{"class":251,"line":283},[249,13883,7610],{},[249,13885,13886],{"class":251,"line":288},[249,13887,3877],{},[249,13889,13890],{"class":251,"line":294},[249,13891,1124],{},[249,13893,13894],{"class":251,"line":300},[249,13895,262],{"emptyLinePlaceholder":261},[249,13897,13898],{"class":251,"line":306},[249,13899,7627],{},[10,13901,13902,7633,13904,2126,13906,7640],{},[172,13903,7632],{},[172,13905,7636],{},[172,13907,7639],{},[164,13909,13910],{"className":3797,"code":7643,"language":3799,"meta":170,"style":170},[172,13911,13912,13916],{"__ignoreMap":170},[249,13913,13914],{"class":251,"line":252},[249,13915,7650],{},[249,13917,13918],{"class":251,"line":258},[249,13919,7655],{},[10,13921,7658],{},[164,13923,13924],{"className":3797,"code":7661,"language":3799,"meta":170,"style":170},[172,13925,13926,13930,13934,13938],{"__ignoreMap":170},[249,13927,13928],{"class":251,"line":252},[249,13929,7668],{},[249,13931,13932],{"class":251,"line":258},[249,13933,262],{"emptyLinePlaceholder":261},[249,13935,13936],{"class":251,"line":265},[249,13937,7677],{},[249,13939,13940],{"class":251,"line":271},[249,13941,7682],{},[10,13943,7685],{},[164,13945,13946],{"className":3797,"code":7688,"language":3799,"meta":170,"style":170},[172,13947,13948],{"__ignoreMap":170},[249,13949,13950],{"class":251,"line":252},[249,13951,7688],{},[28,13953,7698],{"id":7697},[10,13955,7701,13956,7705],{},[172,13957,7704],{},[164,13959,13960],{"className":3797,"code":7708,"language":3799,"meta":170,"style":170},[172,13961,13962,13966,13970,13974,13978,13982,13986,13990,13994,13998],{"__ignoreMap":170},[249,13963,13964],{"class":251,"line":252},[249,13965,7586],{},[249,13967,13968],{"class":251,"line":258},[249,13969,7591],{},[249,13971,13972],{"class":251,"line":265},[249,13973,7596],{},[249,13975,13976],{"class":251,"line":271},[249,13977,3877],{},[249,13979,13980],{"class":251,"line":277},[249,13981,7605],{},[249,13983,13984],{"class":251,"line":283},[249,13985,7610],{},[249,13987,13988],{"class":251,"line":288},[249,13989,3877],{},[249,13991,13992],{"class":251,"line":294},[249,13993,1124],{},[249,13995,13996],{"class":251,"line":300},[249,13997,262],{"emptyLinePlaceholder":261},[249,13999,14000],{"class":251,"line":306},[249,14001,7751],{},[10,14003,14004,7756],{},[172,14005,7704],{},[164,14007,14008],{"className":3797,"code":7759,"language":3799,"meta":170,"style":170},[172,14009,14010,14014],{"__ignoreMap":170},[249,14011,14012],{"class":251,"line":252},[249,14013,7766],{},[249,14015,14016],{"class":251,"line":258},[249,14017,7771],{},[10,14019,7774],{},[164,14021,14022],{"className":3797,"code":7777,"language":3799,"meta":170,"style":170},[172,14023,14024,14028,14032,14036],{"__ignoreMap":170},[249,14025,14026],{"class":251,"line":252},[249,14027,7784],{},[249,14029,14030],{"class":251,"line":258},[249,14031,262],{"emptyLinePlaceholder":261},[249,14033,14034],{"class":251,"line":265},[249,14035,7793],{},[249,14037,14038],{"class":251,"line":271},[249,14039,7798],{},[10,14041,14042,7803,14044,2561,14046,2561,14048,7813],{},[172,14043,7704],{},[172,14045,7806],{},[172,14047,7809],{},[172,14049,7812],{},[10,14051,7816,14052,7820],{},[172,14053,7819],{},[10,14055,7823,14056,7829],{},[151,14057,7828],{"href":7826,"rel":14058},[155],[28,14060,7833],{"id":7832},[10,14062,7836],{},[164,14064,14065],{"className":3797,"code":7839,"language":3799,"meta":170,"style":170},[172,14066,14067],{"__ignoreMap":170},[249,14068,14069],{"class":251,"line":252},[249,14070,7839],{},[10,14072,7848],{},[470,14074,14075,14079,14085,14089],{},[473,14076,14077,7855],{},[172,14078,7806],{},[473,14080,14081,7860,14083,7864],{},[172,14082,4047],{},[172,14084,7863],{},[473,14086,14087,7870],{},[172,14088,7869],{},[473,14090,7873],{},[10,14092,7876,14093,7879],{},[172,14094,7704],{},[28,14096,465],{"id":465},[470,14098,14099,14103,14105,14109,14113],{},[473,14100,14101,7888],{},[172,14102,7575],{},[473,14104,7891],{},[473,14106,14107,7896],{},[172,14108,7704],{},[473,14110,14111,7901],{},[172,14112,7704],{},[473,14114,7904],{},[10,14116,7907],{},[499,14118,501],{},{"title":170,"searchDepth":258,"depth":258,"links":14120},[14121,14122,14123,14124,14125],{"id":7550,"depth":258,"text":7551},{"id":7569,"depth":258,"text":7569},{"id":7697,"depth":258,"text":7698},{"id":7832,"depth":258,"text":7833},{"id":465,"depth":258,"text":465},{},{"title":7537,"description":7917},[4482],{"id":7927,"title":7928,"body":14130,"description":8340,"extension":517,"meta":14452,"navigation":261,"path":8342,"publishDate":8343,"published":261,"seo":14453,"stem":8345,"tags":14454,"thumbnail":8347,"updated":8348,"__hash__":8349},{"type":7,"value":14131,"toc":14444},[14132,14134,14138,14140,14144,14148,14150,14152,14156,14162,14164,14168,14172,14180,14182,14218,14222,14234,14236,14240,14254,14256,14288,14296,14310,14314,14316,14318,14358,14370,14378,14388,14394,14406,14408,14412,14438,14442],[10,14133,12],{},[10,14135,7935,14136,7938],{},[172,14137,7459],{},[28,14139,7942],{"id":7941},[10,14141,14142,7947],{},[172,14143,7459],{},[10,14145,7950,14146,7953],{},[172,14147,7459],{},[10,14149,7956],{},[28,14151,7959],{"id":7959},[10,14153,7962,14154,7965],{},[172,14155,7459],{},[470,14157,14158,14160],{},[473,14159,7970],{},[473,14161,7973],{},[28,14163,7970],{"id":7970},[10,14165,7978,14166,7981],{},[172,14167,7459],{},[10,14169,7984,14170,7987],{},[172,14171,7195],{},[164,14173,14174],{"className":3797,"code":7990,"language":3799,"meta":170,"style":170},[172,14175,14176],{"__ignoreMap":170},[249,14177,14178],{"class":251,"line":252},[249,14179,7990],{},[10,14181,7999],{},[164,14183,14184],{"className":3797,"code":8002,"language":3799,"meta":170,"style":170},[172,14185,14186,14190,14194,14198,14202,14206,14210,14214],{"__ignoreMap":170},[249,14187,14188],{"class":251,"line":252},[249,14189,7172],{},[249,14191,14192],{"class":251,"line":258},[249,14193,3998],{},[249,14195,14196],{"class":251,"line":265},[249,14197,8017],{},[249,14199,14200],{"class":251,"line":271},[249,14201,8022],{},[249,14203,14204],{"class":251,"line":277},[249,14205,3877],{},[249,14207,14208],{"class":251,"line":283},[249,14209,1124],{},[249,14211,14212],{"class":251,"line":288},[249,14213,262],{"emptyLinePlaceholder":261},[249,14215,14216],{"class":251,"line":294},[249,14217,8039],{},[10,14219,8042,14220,8046],{},[172,14221,8045],{},[10,14223,14224,8052,14226,8055,14228,8058,14230,8055,14232,8065],{},[172,14225,8051],{},[172,14227,7459],{},[172,14229,7195],{},[172,14231,8061],{},[172,14233,8064],{},[28,14235,7973],{"id":7973},[10,14237,8070,14238,8073],{},[172,14239,7459],{},[470,14241,14242,14248],{},[473,14243,8078,14244,8081,14246,8085],{},[172,14245,7459],{},[172,14247,8084],{},[473,14249,8088,14250,8055,14252,8093],{},[172,14251,7459],{},[172,14253,4047],{},[10,14255,8096],{},[164,14257,14258],{"className":3797,"code":8099,"language":3799,"meta":170,"style":170},[172,14259,14260,14264,14268,14272,14276,14280,14284],{"__ignoreMap":170},[249,14261,14262],{"class":251,"line":252},[249,14263,8106],{},[249,14265,14266],{"class":251,"line":258},[249,14267,262],{"emptyLinePlaceholder":261},[249,14269,14270],{"class":251,"line":265},[249,14271,8115],{},[249,14273,14274],{"class":251,"line":271},[249,14275,8120],{},[249,14277,14278],{"class":251,"line":277},[249,14279,1124],{},[249,14281,14282],{"class":251,"line":283},[249,14283,262],{"emptyLinePlaceholder":261},[249,14285,14286],{"class":251,"line":288},[249,14287,8133],{},[10,14289,8136,14290,8139,14292,8143,14294,8046],{},[172,14291,8061],{},[172,14293,8142],{},[172,14295,8045],{},[1901,14297,14298],{},[10,14299,14300,2126,14302,8155,14304,8158,14306,8162,14308,8165],{},[172,14301,8152],{},[172,14303,4738],{},[172,14305,8084],{},[172,14307,8161],{},[172,14309,8084],{},[10,14311,8168,14312,8171],{},[172,14313,7459],{},[28,14315,8174],{"id":8174},[10,14317,8177],{},[164,14319,14320],{"className":3797,"code":8180,"language":3799,"meta":170,"style":170},[172,14321,14322,14326,14330,14334,14338,14342,14346,14350,14354],{"__ignoreMap":170},[249,14323,14324],{"class":251,"line":252},[249,14325,7172],{},[249,14327,14328],{"class":251,"line":258},[249,14329,3998],{},[249,14331,14332],{"class":251,"line":265},[249,14333,8017],{},[249,14335,14336],{"class":251,"line":271},[249,14337,8022],{},[249,14339,14340],{"class":251,"line":277},[249,14341,3877],{},[249,14343,14344],{"class":251,"line":283},[249,14345,1124],{},[249,14347,14348],{"class":251,"line":288},[249,14349,262],{"emptyLinePlaceholder":261},[249,14351,14352],{"class":251,"line":294},[249,14353,8215],{},[249,14355,14356],{"class":251,"line":300},[249,14357,8133],{},[10,14359,14360,8225,14362,8228,14364,8232,14366,2557,14368,8237],{},[172,14361,8224],{},[172,14363,8051],{},[172,14365,8231],{},[172,14367,7459],{},[172,14369,7195],{},[10,14371,8136,14372,8139,14374,2576,14376,8246],{},[172,14373,7459],{},[172,14375,8084],{},[172,14377,8142],{},[10,14379,8249,14380,8139,14382,8254,14384,8257,14386,8260],{},[172,14381,7459],{},[172,14383,4047],{},[172,14385,8061],{},[172,14387,4227],{},[10,14389,8263,14390,8267,14392,8270],{},[172,14391,8266],{},[172,14393,7459],{},[164,14395,14396],{"className":3797,"code":8273,"language":3799,"meta":170,"style":170},[172,14397,14398,14402],{"__ignoreMap":170},[249,14399,14400],{"class":251,"line":252},[249,14401,8280],{},[249,14403,14404],{"class":251,"line":258},[249,14405,8285],{},[28,14407,465],{"id":465},[10,14409,14410,8292],{},[172,14411,7459],{},[470,14413,14414,14422,14430,14432],{},[473,14415,14416,8299,14418,8055,14420,8085],{},[172,14417,8051],{},[172,14419,7459],{},[172,14421,7195],{},[473,14423,14424,8308,14426,8311,14428,8093],{},[172,14425,8231],{},[172,14427,8084],{},[172,14429,4047],{},[473,14431,8316],{},[473,14433,8319,14434,3713,14436,8324],{},[172,14435,8266],{},[172,14437,7459],{},[10,14439,14440,8329],{},[172,14441,7459],{},[499,14443,501],{},{"title":170,"searchDepth":258,"depth":258,"links":14445},[14446,14447,14448,14449,14450,14451],{"id":7941,"depth":258,"text":7942},{"id":7959,"depth":258,"text":7959},{"id":7970,"depth":258,"text":7970},{"id":7973,"depth":258,"text":7973},{"id":8174,"depth":258,"text":8174},{"id":465,"depth":258,"text":465},{},{"title":7928,"description":8340},[4482],[14456,14472,14487,14504,14520,14537,15179],{"id":14457,"title":14458,"author":14459,"body":14460,"description":170,"extension":517,"meta":14464,"navigation":261,"path":14465,"publishDate":3157,"published":261,"publisher":14466,"seo":14467,"stem":14468,"tags":14469,"__hash__":14471},"books\u002Fbooks\u002F2026\u002Fnetwork-and-tcp-ip-basics-third-edition.md","スラスラわかるネットワーク＆TCP\u002FIPのきほん","リブロワークス",{"type":7,"value":14461,"toc":14462},[],{"title":170,"searchDepth":258,"depth":258,"links":14463},[],{},"\u002Fbooks\u002F2026\u002Fnetwork-and-tcp-ip-basics-third-edition","SBクリエイティブ",{"title":14458,"description":170},"books\u002F2026\u002Fnetwork-and-tcp-ip-basics-third-edition",[14470],"ネットワーク","xbhb-FmdB9ZUXSWhb6ZiW-gZhC-vBAHVIBUepRuVli8",{"id":14473,"title":14474,"author":14475,"body":14476,"description":170,"extension":517,"meta":14480,"navigation":261,"path":14481,"publishDate":14482,"published":261,"publisher":526,"seo":14483,"stem":14484,"tags":14485,"__hash__":14486},"books\u002Fbooks\u002F2026\u002Fcodex-cli-story-guide.md","ストーリーで覚えるCodex CLI入門","多佳宮崇志",{"type":7,"value":14477,"toc":14478},[],{"title":170,"searchDepth":258,"depth":258,"links":14479},[],{},"\u002Fbooks\u002F2026\u002Fcodex-cli-story-guide","2026-07-01",{"title":14474,"description":170},"books\u002F2026\u002Fcodex-cli-story-guide",[1234,604],"PEgEg4PTkrDoxH9hQrqXYiZBJ67uDkx0IWREiaDBKPs",{"id":14488,"title":14489,"author":14490,"body":14491,"description":170,"extension":517,"meta":14495,"navigation":261,"path":14496,"publishDate":14497,"published":261,"publisher":14498,"seo":14499,"stem":14500,"tags":14501,"__hash__":14503},"books\u002Fbooks\u002F2026\u002Fdatabase-design-guide.md","達人に学ぶDB設計徹底指南書","ミック",{"type":7,"value":14492,"toc":14493},[],{"title":170,"searchDepth":258,"depth":258,"links":14494},[],{},"\u002Fbooks\u002F2026\u002Fdatabase-design-guide","2026-05-01","翔泳社",{"title":14489,"description":170},"books\u002F2026\u002Fdatabase-design-guide",[14502],"DB設計","OZjkZ3_sun4Iebo7nv_yIq3e-mN3Q4enB_x548F2n6E",{"id":14505,"title":14506,"author":14507,"body":14508,"description":170,"extension":517,"meta":14512,"navigation":261,"path":14513,"publishDate":14514,"published":261,"publisher":526,"seo":14515,"stem":14516,"tags":14517,"__hash__":14519},"books\u002Fbooks\u002F2025\u002Fdjango-rest-framework-textbook.md","現場で使える Django REST Framework の教科書［3.2 LTS 対応版］","横瀬明仁",{"type":7,"value":14509,"toc":14510},[],{"title":170,"searchDepth":258,"depth":258,"links":14511},[],{},"\u002Fbooks\u002F2025\u002Fdjango-rest-framework-textbook","2025-04-30",{"title":14506,"description":170},"books\u002F2025\u002Fdjango-rest-framework-textbook",[14518],"Django","PHo1FMxCs3EYdWF_zT1YpG5RxgBt1hTaxX5W8cHSb7Y",{"id":14521,"title":14522,"author":14523,"body":14524,"description":170,"extension":517,"meta":14528,"navigation":261,"path":14529,"publishDate":14530,"published":261,"publisher":14531,"seo":14532,"stem":14533,"tags":14534,"__hash__":14536},"books\u002Fbooks\u002F2025\u002Fweb-technology-for-professionals-revised-edition.md","［改訂新版］プロになるためのWeb技術入門","小森裕介",{"type":7,"value":14525,"toc":14526},[],{"title":170,"searchDepth":258,"depth":258,"links":14527},[],{},"\u002Fbooks\u002F2025\u002Fweb-technology-for-professionals-revised-edition","2025-03-31","技術評論社",{"title":14522,"description":170},"books\u002F2025\u002Fweb-technology-for-professionals-revised-edition",[14535],"Web","LNFLOzGXkq9b6hCTxytQFYlJnlvvorYY8OPjICfte9g",{"id":14538,"title":14539,"author":14459,"body":14540,"description":15170,"extension":517,"meta":15171,"navigation":261,"path":15172,"publishDate":15173,"published":261,"publisher":15174,"seo":15175,"stem":15176,"tags":15177,"__hash__":15178},"books\u002Fbooks\u002F2025\u002Forganize-learned-from-docker.md","Docker&仮想サーバー完全入門",{"type":7,"value":14541,"toc":15157},[14542,14550,14553,14557,14560,14563,14569,14573,14576,14622,14637,14640,14661,14664,14668,14674,14697,14707,14714,14719,14725,14738,14744,14752,14758,14801,14807,14832,14836,14843,14878,14884,14887,14890,14943,14946,14953,14967,14970,14987,14997,15021,15024,15031,15045,15056,15075,15087,15091,15094,15101,15107,15110,15113,15115,15118,15121,15151,15154],[10,14543,14544,14545,14549],{},"『",[151,14546,14539],{"href":14547,"rel":14548},"https:\u002F\u002Fbook.impress.co.jp\u002Fbooks\u002F1121101138",[155],"』を読了したため、本書を通して学んだことをまとめます。",[10,14551,14552],{},"まだ1周目で理解が浅い部分もあるため、Dockerを実際に使いながら必要に応じて追記していきます。",[28,14554,14556],{"id":14555},"dockerでホスト環境への影響を抑える","Dockerでホスト環境への影響を抑える",[10,14558,14559],{},"Dockerを利用すると、アプリケーションに必要なランタイムやライブラリをコンテナ内にまとめられます。",[10,14561,14562],{},"ホストOSへ依存関係を直接インストールする場面を減らせるため、開発環境を整理しやすくなります。また、DockerfileやComposeファイルを共有することで、チーム内で環境を再現しやすくなります。",[2117,14564,14566],{"title":14565,"type":2120},"ホストOSから完全に独立するわけではない",[10,14567,14568],{},"コンテナはホストのカーネルやDocker Engineを利用します。ボリューム、ポート、CPUアーキテクチャなど、ホスト環境との接点がなくなるわけではありません。",[28,14570,14572],{"id":14571},"dockerコマンドで操作対象を明示する","Dockerコマンドで操作対象を明示する",[10,14574,14575],{},"Docker CLIには、操作対象を含めて記述するコマンドがあります。",[164,14577,14579],{"className":1671,"code":14578,"language":1673,"meta":170,"style":170},"docker container run nginx\ndocker image pull nginx\ndocker volume ls\ndocker network ls\n",[172,14580,14581,14594,14604,14613],{"__ignoreMap":170},[249,14582,14583,14585,14588,14591],{"class":251,"line":252},[249,14584,1828],{"class":925},[249,14586,14587],{"class":929}," container",[249,14589,14590],{"class":929}," run",[249,14592,14593],{"class":929}," nginx\n",[249,14595,14596,14598,14600,14602],{"class":251,"line":258},[249,14597,1828],{"class":925},[249,14599,3537],{"class":929},[249,14601,2798],{"class":929},[249,14603,14593],{"class":929},[249,14605,14606,14608,14610],{"class":251,"line":265},[249,14607,1828],{"class":925},[249,14609,3637],{"class":929},[249,14611,14612],{"class":929}," ls\n",[249,14614,14615,14617,14620],{"class":251,"line":271},[249,14616,1828],{"class":925},[249,14618,14619],{"class":929}," network",[249,14621,14612],{"class":929},[10,14623,14624,2561,14627,2561,14630,2561,14633,14636],{},[172,14625,14626],{},"container",[172,14628,14629],{},"image",[172,14631,14632],{},"volume",[172,14634,14635],{},"network","のように対象が明示されるため、何を操作するコマンドなのか把握しやすくなります。",[10,14638,14639],{},"一方で、次の短い形式も現在利用できます。",[164,14641,14643],{"className":1671,"code":14642,"language":1673,"meta":170,"style":170},"docker run nginx\ndocker pull nginx\n",[172,14644,14645,14653],{"__ignoreMap":170},[249,14646,14647,14649,14651],{"class":251,"line":252},[249,14648,1828],{"class":925},[249,14650,14590],{"class":929},[249,14652,14593],{"class":929},[249,14654,14655,14657,14659],{"class":251,"line":258},[249,14656,1828],{"class":925},[249,14658,2798],{"class":929},[249,14660,14593],{"class":929},[10,14662,14663],{},"短い形式を古いという理由だけで避ける必要はありません。学習時には対象を含む形式も知っておくと、CLIの構造を理解しやすいと感じました。",[28,14665,14667],{"id":14666},"docker-compose-v2を利用する","Docker Compose V2を利用する",[10,14669,14670,14671,4188],{},"現在のCompose CLIでは、ハイフンのない",[172,14672,14673],{},"docker compose",[164,14675,14677],{"className":1671,"code":14676,"language":1673,"meta":170,"style":170},"docker compose up\ndocker compose down\n",[172,14678,14679,14688],{"__ignoreMap":170},[249,14680,14681,14683,14685],{"class":251,"line":252},[249,14682,1828],{"class":925},[249,14684,1831],{"class":929},[249,14686,14687],{"class":929}," up\n",[249,14689,14690,14692,14694],{"class":251,"line":258},[249,14691,1828],{"class":925},[249,14693,1831],{"class":929},[249,14695,14696],{"class":929}," down\n",[10,14698,14699,14700,14703,14704,14706],{},"旧Compose V1で使われていた",[172,14701,14702],{},"docker-compose","とはコマンド形式が異なります。Docker DesktopにはCompose CLIが含まれているため、基本的には",[172,14705,14673],{},"を利用します。",[28,14708,14710,14711,4432],{"id":14709},"composeファイルはcomposeyamlを使う","Composeファイルは",[172,14712,14713],{},"compose.yaml",[10,14715,14716,14717,144],{},"Composeファイルの推奨ファイル名は",[172,14718,14713],{},[164,14720,14723],{"className":14721,"code":14722,"language":169,"meta":170},[167],"compose.yaml\n",[172,14724,14722],{"__ignoreMap":170},[10,14726,14727,14730,14731,3924,14734,14737],{},[172,14728,14729],{},"compose.yml","も利用できます。また、",[172,14732,14733],{},"docker-compose.yaml",[172,14735,14736],{},"docker-compose.yml","も後方互換性のためサポートされています。",[10,14739,14740,14741,14743],{},"複数の候補が同じ場所にある場合は",[172,14742,14713],{},"が優先されるため、新しく作る場合はこの名前へ揃えると分かりやすくなります。",[28,14745,14747,14748,14751],{"id":14746},"トップレベルのversionは不要","トップレベルの",[172,14749,14750],{},"version","は不要",[10,14753,14754,14755,14757],{},"以前のComposeファイルでは、先頭に次のような",[172,14756,14750],{},"を書く例がありました。",[164,14759,14761],{"className":1742,"code":14760,"language":1744,"meta":170,"style":170},"version: '3'\n\nservices:\n  web:\n    image: nginx\n",[172,14762,14763,14775,14779,14785,14792],{"__ignoreMap":170},[249,14764,14765,14767,14769,14771,14773],{"class":251,"line":252},[249,14766,14750],{"class":1751},[249,14768,1091],{"class":1002},[249,14770,1003],{"class":1002},[249,14772,122],{"class":929},[249,14774,1009],{"class":1002},[249,14776,14777],{"class":251,"line":258},[249,14778,262],{"emptyLinePlaceholder":261},[249,14780,14781,14783],{"class":251,"line":265},[249,14782,1752],{"class":1751},[249,14784,1755],{"class":1002},[249,14786,14787,14790],{"class":251,"line":271},[249,14788,14789],{"class":1751},"  web",[249,14791,1755],{"class":1002},[249,14793,14794,14797,14799],{"class":251,"line":277},[249,14795,14796],{"class":1751},"    image",[249,14798,1091],{"class":1002},[249,14800,14593],{"class":929},[10,14802,14803,14804,14806],{},"現在、トップレベルの",[172,14805,14750],{},"は後方互換性のために残されたobsoleteな項目です。指定してもComposeは最新のスキーマでファイルを検証するため、新しいComposeファイルでは省略します。",[164,14808,14810],{"className":1742,"code":14809,"language":1744,"meta":170,"style":170},"services:\n  web:\n    image: nginx\n",[172,14811,14812,14818,14824],{"__ignoreMap":170},[249,14813,14814,14816],{"class":251,"line":252},[249,14815,1752],{"class":1751},[249,14817,1755],{"class":1002},[249,14819,14820,14822],{"class":251,"line":258},[249,14821,14789],{"class":1751},[249,14823,1755],{"class":1002},[249,14825,14826,14828,14830],{"class":251,"line":265},[249,14827,14796],{"class":1751},[249,14829,1091],{"class":1002},[249,14831,14593],{"class":929},[28,14833,14835],{"id":14834},"restart-policyは用途に合わせて設定する","restart policyは用途に合わせて設定する",[10,14837,14838,14839,14842],{},"Composeのサービスには、コンテナを再起動する条件を",[172,14840,14841],{},"restart","で設定できます。",[164,14844,14846],{"className":1742,"code":14845,"language":1744,"meta":170,"style":170},"services:\n  web:\n    image: nginx\n    restart: always\n",[172,14847,14848,14854,14860,14868],{"__ignoreMap":170},[249,14849,14850,14852],{"class":251,"line":252},[249,14851,1752],{"class":1751},[249,14853,1755],{"class":1002},[249,14855,14856,14858],{"class":251,"line":258},[249,14857,14789],{"class":1751},[249,14859,1755],{"class":1002},[249,14861,14862,14864,14866],{"class":251,"line":265},[249,14863,14796],{"class":1751},[249,14865,1091],{"class":1002},[249,14867,14593],{"class":929},[249,14869,14870,14873,14875],{"class":251,"line":271},[249,14871,14872],{"class":1751},"    restart",[249,14874,1091],{"class":1002},[249,14876,14877],{"class":929}," always\n",[10,14879,14880,14883],{},[172,14881,14882],{},"always","を指定したコンテナは、停止した場合やDockerデーモンが再起動した場合に再起動されます。",[10,14885,14886],{},"常時稼働が必要なサービスでは便利ですが、学習用コンテナへ一律に指定すると、Docker起動時に意図しないコンテナまで立ち上がることがあります。必要性を考えて設定することが大切です。",[10,14888,14889],{},"主なrestart policyには次があります。",[38,14891,14892,14902],{},[41,14893,14894],{},[44,14895,14896,14899],{},[47,14897,14898],{},"値",[47,14900,14901],{},"動作",[57,14903,14904,14914,14924,14933],{},[44,14905,14906,14911],{},[62,14907,14908],{},[172,14909,14910],{},"no",[62,14912,14913],{},"自動的に再起動しない",[44,14915,14916,14921],{},[62,14917,14918],{},[172,14919,14920],{},"on-failure",[62,14922,14923],{},"エラー終了した場合に再起動する",[44,14925,14926,14930],{},[62,14927,14928],{},[172,14929,14882],{},[62,14931,14932],{},"停止した場合に常に再起動する",[44,14934,14935,14940],{},[62,14936,14937],{},[172,14938,14939],{},"unless-stopped",[62,14941,14942],{},"明示的に停止されていない限り再起動する",[28,14944,14945],{"id":14945},"コンテナのログを確認する",[10,14947,14948,14949,14952],{},"Composeで起動したサービスのログは",[172,14950,14951],{},"docker compose logs","で確認できます。",[164,14954,14956],{"className":1671,"code":14955,"language":1673,"meta":170,"style":170},"docker compose logs\n",[172,14957,14958],{"__ignoreMap":170},[249,14959,14960,14962,14964],{"class":251,"line":252},[249,14961,1828],{"class":925},[249,14963,1831],{"class":929},[249,14965,14966],{"class":929}," logs\n",[10,14968,14969],{},"サービスを指定すると、対象のログだけを表示できます。",[164,14971,14973],{"className":1671,"code":14972,"language":1673,"meta":170,"style":170},"docker compose logs web\n",[172,14974,14975],{"__ignoreMap":170},[249,14976,14977,14979,14981,14984],{"class":251,"line":252},[249,14978,1828],{"class":925},[249,14980,1831],{"class":929},[249,14982,14983],{"class":929}," logs",[249,14985,14986],{"class":929}," web\n",[10,14988,14989,14990,14993,14994,4188],{},"ログを継続して追いかける場合は",[172,14991,14992],{},"--follow","、末尾の行数を限定する場合は",[172,14995,14996],{},"--tail",[164,14998,15000],{"className":1671,"code":14999,"language":1673,"meta":170,"style":170},"docker compose logs --follow --tail 100 web\n",[172,15001,15002],{"__ignoreMap":170},[249,15003,15004,15006,15008,15010,15013,15016,15019],{"class":251,"line":252},[249,15005,1828],{"class":925},[249,15007,1831],{"class":929},[249,15009,14983],{"class":929},[249,15011,15012],{"class":929}," --follow",[249,15014,15015],{"class":929}," --tail",[249,15017,15018],{"class":1772}," 100",[249,15020,14986],{"class":929},[28,15022,15023],{"id":15023},"イメージを再ビルドする",[10,15025,15026,15027,15030],{},"Composeでイメージをビルドするには",[172,15028,15029],{},"docker compose build","を使います。",[164,15032,15034],{"className":1671,"code":15033,"language":1673,"meta":170,"style":170},"docker compose build\n",[172,15035,15036],{"__ignoreMap":170},[249,15037,15038,15040,15042],{"class":251,"line":252},[249,15039,1828],{"class":925},[249,15041,1831],{"class":929},[249,15043,15044],{"class":929}," build\n",[10,15046,15047,15048,15051,15052,15055],{},"コンテナの起動前にビルドも実行したい場合は、",[172,15049,15050],{},"docker compose up","へ",[172,15053,15054],{},"--build","を付けられます。",[164,15057,15059],{"className":1671,"code":15058,"language":1673,"meta":170,"style":170},"docker compose up --detach --build\n",[172,15060,15061],{"__ignoreMap":170},[249,15062,15063,15065,15067,15069,15072],{"class":251,"line":252},[249,15064,1828],{"class":925},[249,15066,1831],{"class":929},[249,15068,1834],{"class":929},[249,15070,15071],{"class":929}," --detach",[249,15073,15074],{"class":929}," --build\n",[10,15076,15077,15079,15080,4044,15083,15086],{},[172,15078,15050],{},"は、サービスの設定やイメージが変更されている場合にコンテナを再作成します。ただし、Dockerfileやビルド対象を確実に再ビルドしてから起動したい場合は、",[172,15081,15082],{},"build",[172,15084,15085],{},"up --build","を明示すると意図が分かりやすくなります。",[28,15088,15090],{"id":15089},"dev-containerで開発環境をコンテナ化する","Dev Containerで開発環境をコンテナ化する",[10,15092,15093],{},"VS CodeのDev Containers拡張機能を使うと、コンテナを開発環境として利用できます。",[10,15095,15096,15097,15100],{},"プロジェクト内の",[172,15098,15099],{},".devcontainer\u002Fdevcontainer.json","へ設定を記述し、コンテナ内のランタイム、ツール、VS Code拡張機能などを揃えられます。",[164,15102,15105],{"className":15103,"code":15104,"language":169,"meta":170},[167],".devcontainer\u002F\n  devcontainer.json\n",[172,15106,15104],{"__ignoreMap":170},[10,15108,15109],{},"ソースコードをコンテナへマウントし、ターミナル、補完、コードナビゲーション、デバッグなどを普段のVS Codeと近い操作感で利用できます。",[10,15111,15112],{},"環境構築手順を文章だけで共有するよりも、実行環境そのものを設定として共有できる点が便利だと感じました。",[28,15114,465],{"id":465},[10,15116,15117],{},"本書を通して、Dockerの基本操作だけでなく、Composeによる複数コンテナの管理や、開発環境をコンテナ化する考え方を学べました。",[10,15119,15120],{},"特に、次の点を今後の開発でも意識したいです。",[470,15122,15123,15126,15131,15136,15142,15145,15148],{},[473,15124,15125],{},"Docker CLIで何を操作しているか理解する",[473,15127,15128,15129,4432],{},"Compose V2の",[172,15130,14673],{},[473,15132,14710,15133,15135],{},[172,15134,14713],{},"へ揃える",[473,15137,15138,15139,15141],{},"不要な",[172,15140,14750],{},"を記述しない",[473,15143,15144],{},"restart policyを用途に合わせて設定する",[473,15146,15147],{},"ログ確認と再ビルドのコマンドを使い分ける",[473,15149,15150],{},"Dev Containerで再現可能な開発環境を試す",[10,15152,15153],{},"Dockerはコマンドを覚えるだけでなく、イメージ、コンテナ、ボリューム、ネットワークの関係を実際に操作しながら理解していきたいです。",[499,15155,15156],{},"html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .swJcz, html code.shiki .swJcz{--shiki-light:#E53935;--shiki-default:#F07178;--shiki-dark:#F07178}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .sbssI, html code.shiki .sbssI{--shiki-light:#F76D47;--shiki-default:#F78C6C;--shiki-dark:#F78C6C}",{"title":170,"searchDepth":258,"depth":258,"links":15158},[15159,15160,15161,15162,15164,15165,15166,15167,15168,15169],{"id":14555,"depth":258,"text":14556},{"id":14571,"depth":258,"text":14572},{"id":14666,"depth":258,"text":14667},{"id":14709,"depth":258,"text":15163},"Composeファイルはcompose.yamlを使う",{"id":14746,"depth":258,"text":14746},{"id":14834,"depth":258,"text":14835},{"id":14945,"depth":258,"text":14945},{"id":15023,"depth":258,"text":15023},{"id":15089,"depth":258,"text":15090},{"id":465,"depth":258,"text":465},"『Docker&仮想サーバー完全入門』を読了したため、本書を通して学んだことをまとめます。",{},"\u002Fbooks\u002F2025\u002Forganize-learned-from-docker","2025-02-22","インプレス",{"title":14539,"description":15170},"books\u002F2025\u002Forganize-learned-from-docker",[2482],"tZTXcHlrKtyN5T4H4BpRH6Dc272-Srw05uyFSfG7w5Q",{"id":15180,"title":15181,"author":15182,"body":15183,"description":170,"extension":517,"meta":15187,"navigation":261,"path":15188,"publishDate":15189,"published":261,"publisher":15190,"seo":15191,"stem":15192,"tags":15193,"__hash__":15194},"books\u002Fbooks\u002F2024\u002Fhow-networks-connect-second-edition.md","ネットワークはなぜつながるのか　第２版","戸根勤",{"type":7,"value":15184,"toc":15185},[],{"title":170,"searchDepth":258,"depth":258,"links":15186},[],{},"\u002Fbooks\u002F2024\u002Fhow-networks-connect-second-edition","2024-05-31","日経BP",{"title":15181,"description":170},"books\u002F2024\u002Fhow-networks-connect-second-edition",[14470],"SIuIZbtr-w2AzFZh6gTb7u043lu97IMLINksxROAke0",1789994574956]