Claude.aiを2週間で3倍高速化した方法
How we made claude.ai 3x faster in two weeks (claude.dev)
要約
Anthropicのエンジニアリングチームは、Claude.aiとそのデスクトップアプリのコアユーザーエクスペリエンスを2週間のスプリントで約3倍高速化しました。この改善は、Claude自身をパフォーマンス監視、ボトルネック特定、ベンチマーク構築、ソリューション提案に活用することで達成されました。結果として、ユーザーの待ち時間を大幅に削減し、全体的なパフォーマンスを向上させました。
全文翻訳
claude.ai を2週間で3倍高速化した方法
この8月、私たちはclaude.aiとClaudeデスクトップアプリのコアユーザーエクスペリエンスを、2週間のスプリントで約3倍高速化しました。ユーザーからは遅いという声があり、それは正しかったのです。私たちはClaudeをすべてのスレッドに配置し、すべてを単一のSlackチャンネルで実行しました。
私たちはユーザーアクティビティの95%を占める4つのジャーニーに焦点を当てました。75パーセンタイルで、claude.aiの新規ロードで入力可能なページが表示されるまでの時間は3.1秒から0.55秒に、Claude Codeセッションの開始は0.8秒から0.3秒に、Claude Coworkクラウドセッションのロードは2.6秒から0.73秒に短縮されました。全体として、これにより毎日数万時間ものユーザーの待ち時間が節約されると推定しています。
コアユーザーのジャーニー、p75
リアルユーザーモニタリング、プラットフォームおよび製品ごと、8月13日 vs 8月27日
私たちはClaude Tag(ベータ版)を使用し、Opus 5.5に匹敵する内部リサーチモデルを実行しました。Claudeはボトルネックを発見し、ベンチマークを構築し、改善をデプロイし、すべてのデプロイを監視しました。目標設定、トレードオフの決定、およびすべての変更の承認によって、私たちは方向性を定めました。このアプローチにより、顧客に影響を与えるインシデントやロールバックなしに、3000以上の変更をマージしました。この記事では、私たちが何をデプロイし、どのように測定し、安全に実行するためにClaudeと構築したループについて説明します。
短期集中プロジェクト
スプリントの前に、私たちは以下の常設指示を持つSlackチャンネルを作成しました。
@Claude あなたの仕事は、claude.aiウェブサイトとデスクトップアプリのパフォーマンスに関連するすべてのことを促進することです。あなたの責任には、パフォーマンスの低下を監視するデプロイの監視、既存のテレメトリの精度と網羅性の評価、適切にキュレーションされたオブザーバビリティダッシュボードの維持、観察された問題や容易に解決できる問題に対するプロアクティブなソリューションの実装、パフォーマンスプロジェクトの機会の提案、そして人間のチームメイトとのコミュニケーションが含まれます。[…]
このチャンネルの最終目標は、あなたが可能な限り自律的になることです。しかし、今日、それがまだ不可能であることを私たちは知っています。
ClaudeにDatadog MCPサーバーを介して使用状況データを分析するように依頼しました。Claudeは最も影響力の大きい4つのユーザー体験を特定しました:アプリの起動、会話の開始、既存の会話のロード、メッセージの送信です。Webとデスクトップ、そして私たちの製品全体で、これらの体験は13の異なる測定項目になりました。ベースラインを確立するために、それらが直接比較可能になるまでインストルメンテーションを追加しました:各体験はユーザーインタラクションで始まり、結果がレンダリングされると終了し、クライアントとサーバーの作業を明確に区別しました。
スプリントは、それぞれ特定のジャーニーを対象とした約20の厳選されたプロジェクトのリストから開始しました。Claudeは各プロジェクトの影響をミリ秒単位で推定し、私たちはそれらの推定値を集計してスプリントの目標を設定しました。プロジェクトの中にはかなり大規模なものもありましたが、2週間以内にほとんどを達成できると考えていました。
私たちは3日目までに13のターゲットのうち12を達成しました。
計画されたプロジェクトは早期に着地しました。起動を高速化するために、HTMLに静的なコンポーザーを組み込み、ユーザーがReactの初期化中にタイプできるようにしました。また、V8コードキャッシュをプリコンパイルしたため、デスクトップシェルがメインプロセスで最初から再コンパイルする必要がなくなりました。ナビゲーションを高速化するために、会話間でコンポーザーをマウントしたままにし、ホバー時にセッションをプリフェッチし、サイドバーの再レンダリングを90%削減しました。
私たちはClaudeが機会を発見し、新しいワークストリームを提案するための余地も残していました。それらのワークストリームはすぐに独自のフルプロジェクトに発展し、当初の目標をはるかに超えました。そこで、私たちは新しい目標を設定し、さらに測定すべきものを探しました。
@Claude 元のプロジェクトリストのほぼすべてのプロジェクトと、さらに多くのプロジェクトに資金を提供することになりました。リフレッシュしましょう […] まだ探求していないことは何ですか?ヒルクライムできる場所はどこですか?現時点で最も機会があるのはどこですか? […] クレイジーなアイデアも歓迎します。
何でもヒルクライムできる
最初から、私たちはデプロイのケイデンスよりも速くイテレーションしたいと考えていました。Claudeは数時間、場合によっては一晩中非同期で作業でき、フィールドリードを待たずにプロトタイプを検証できるようにしたかったのです。それを達成するために、ラボでパフォーマンスを測定する他の方法を探しました。
Samが最初のリードを見つけました。
#claude-apps-perf · スレッド
-
Sam12:34 PM
ウォールクロックタイミングの代わりに何ができますか?例えばJS命令数を測定できますか?
-
ClaudeApp12:42 PM
はい。純粋なJSのホットパスでは、命令数を直接測定できます:
node --predictableでValgrind下でベンチマークを実行し、チェックイン済みのベースラインと比較します。統計は不要です。ブラウザパスではChromium下での命令カウントはありませんが、他の決定論的なカウントの階層があります:インタラクションごとのReactコミット数、V8の正確なカバレッジからの関数呼び出し数、レイアウトとスタイルの再計算数、DOMミューテーション。どれを最初に知りたいですか?
-
Sam12:49 PM
Valgrind +
Ir+--predictableを1つのスレッドで、ブラウザ/Reactベンチをそれぞれ新しいスレッドで探求しましょう。すべてで私にピンしてください。私たちが何を求めているか知っているはずです。始めましょう。
実際の会話から再現。
11分後、命令数、V8呼び出し数、Reactコミット数、スタイル再計算数、DOMミューテーションの5つのスレッドがそれぞれ異なる測定に焦点を当てて実行されていました。
私たちは新しいベンチマークをすべて懐疑的に扱いました。それぞれに2つの仕事がありました:第一に、Claudeがラボで動かせるメトリック。第二に、CIのガードレールであり、数値を下げることしかできませんでした。ベンチマークが不安定だったり、ユーザーのレイテンシと実際には相関していなかったりした場合、Claudeが間違った丘を登るのを防ぐために、それを破棄しました。
@Claude これらのそれぞれに対するヒルクライムが、測定可能なウォールクロックパフォーマンスの向上につながることを証明してください。証明できないベンチは出荷しません。
ウォールクロック時間はユーザーが感じるものですが、ノイズが多く、ミリ秒はCIゲートとして使用するには不安定すぎます。命令数は決定論的であるため魅力的でしたが、ウォールクロック時間と相関していることをClaudeに証明してもらう必要がありました。
そこで、Claudeに2つのホットパスでカウントを減らすように依頼しました:会話のメッセージツリーを組み立てるルーチンと、Claude Code出力のステータスラインのスキャナーです。ClaudeはValgrindで両方をプロファイルし、最初のパスの命令の4分の1がメガモルフィックな辞書ルックアップであり、同じメッセージIDを3回別々に解決していることを発見しました。
1時間後、Claudeは両方のパスで命令数を48%と31%削減し、ウォールクロック時間は78%と44%減少しました。私たちは2つの新しいラチェットをチェックインしました。それ以降、それらのパスの命令数を増加させるPRはCIで失敗し、カウントが下がると毎日実行されるジョブが各上限を引き下げました。
カウントはクロックと相関するか?
CPU命令数 vs ウォールクロック時間
これがスプリントの中心的な教訓につながりました。Claudeを使用すると、何かを測定することが、それを扱いやすくします。
測定はかつてステップゼロでした:メトリックを追加し、データがロールインするのを待ち、それから問題の理解を開始しました。Claudeを使用すると、それはクライムのステップワンです。Claudeがビートすべき数値を得るとすぐに、最適化を開始できました。これにより、私たちができる最もレバレッジの高いことは、測定するものを増やすことでした。
ループ、スレッドごと
これらすべてが同じSlackチャンネルで実行され、複数のエンジニアとClaudeが各スレッドでジャムっていました。そこから、スプリントはループに落ち着きました。
- 誰かがジャーニーの遅い部分についてスレッドを開き、しばしばスクリーンショットや録画を添えます。
- Claudeはフローをトレースし、問題を示すベンチマークを見つけるか構築します。
- ラボで有望な結果が得られると、ClaudeはPRを提示します。多くの場合、リスクとレビューのためにサイズ分けされたものが複数あり、ユーザーに見えるものはすべてフラグの後ろに隠されます。
- デプロイ後、Claudeはデプロイを監視し、フィールドデータを読み取ります。
- パフォーマンスが向上した場合、Claudeはベンチマークを下げて勝利を確定します。そうでなければ、フラグをオフにしてイテレーションします。
- その後、同じジャーニーで次の遅い場所を探します。
ループ内の1つのスレッド
誰かがスレッドを開き、Claudeがそこから引き継ぎます。
例:誰かがサイドバーの行がページロード後にポップインする画面録画を共有しました。チャットとCoworkの行は異なる時間に解決され、ページがジャギーに感じられました。既存のモニターのどれもそれを検出しませんでした。最も近いものはCumulative Layout Shiftでしたが、各シフトはわずか0.008しかスコアされず、0.1の良い閾値をはるかに下回っていました。
Issacは、基盤となるLayout Instability APIを直接参照するというアイデアを持っていました。Claudeは、各layout-shiftエントリのsourcesを名前付きリージョン(例:サイドバー、トランスクリプト)とフェーズ(例:ファーストペイント前、タイプ可能後)にマッピングするテレメトリイベントを作成しました。ポップアップしたサイドバーでページを開き、サイドバーのデータをファーストペイント後に保持し、名前付きリージョンでのシフトがあった場合に失敗する統合テストを追加しました。Claudeはそれをベンチマークとして修正を証明しました:テストはメインで20回中20回赤くなり、PRでは20回中20回緑になりました。
イベントがデプロイされた後、Claudeはフィールドデータを読み取り、Webページロードの31%で、ユーザーインタラクションなしに、ページが使用可能になった後に何かが移動したことを発見しました。そこから、Claudeは名前で原因を調査しました:遅れて到着したヘッダー行、ユーザー名がロードされたときに横にスライドしたキャレット、スクロールバーが表示されたときに移動したリスト。Claudeはトップの違反者をバッチで修正し、それらがなくなったときに次のバッチを見つけました。
[動画]
[画像: claude.aiサイドバーのロードのサイドバイサイド録画。前は、行が遅れて到着し再配置されます:10行がジャンプし、9行が表示され、4行が消えます。後では、行は留まる場所に埋まり、何も動きません。]
図Aサイドバーのジャーク、修正前後 · スロットル4G
それは1つのスレッドでした。スプリント中、私たちは同時に150以上のスレッドを実行しました。
水平スケーリング
ループが1つのスレッドで機能すると、より多くのスレッドで実行するのは、それらを開くだけの問題でした。元のリクエストが満たされた後もスレッドを閉じずに、Claudeは続行しました。個々のスレッドは50、時には100の最適化PRを提示しました。Claudeが、別の調査や夜間ジョブの一部として、自分で見つけた機会を追いかけるために新しいスレッドを開くことが増えました。チャンネルにいたエンジニアの一人、Shelleyは、「[このモデル]は数字の悪魔です」と観察しました。
見つかったすべての測定値が改善につながりました。ClaudeはReactフックのセンサスを実行し、コンポーザーのタイピングパスで6,900のフックと900のストアサブスクリプションを発見し、キーストロークごとに再レンダリングしていました。Claudeはスタイル再計算をカウントし、単一の:root:has()セレクターがDOMの変更ごとに24ミリ秒を追加していることを発見しました。Claudeはファーストペイント後のコードパスをトレースし、50万回の隠れたリロードを引き起こしていた残りのlocation.reload()を発見しました。Claudeはアイドルタブからのプロファイラサンプルを読み取り、メインスレッド上で毎分2回クローンされていた同一のキャッシュスナップショットを発見しました。
スレッドがどこにつながるかはめったにわかりませんでした。CPUのひっち(一時的な遅延)のスイープ中に、Claudeはコードブロックをハイライトするとページが約1秒間フリーズする可能性があることに気づきました。ラボで掘り下げると、原因が判明しました:emダッシュです。返信のマークダウンにemダッシュやカーリークォートのような非ASCII文字が含まれている場合、V8は文字列全体をUTF-16として保存し、すべての構文ハイライト正規表現を遅い2バイトパスに置きました。Claudeは、ハイライトする前に各コードブロックを1バイト文字列にコピーする20行の変更でこれを修正しました。
ページ上の最初のコードブロックのハイライト
修正前後でのメインスレッドブロック時間
2週目になると、日次アップデートにさえ出力を要約するのが困難になりました。最も忙しい日には、200以上の変更が着地しました。Claudeは新しいベンチマークを提案し続けました。PRの約3分の1には追加のテレメトリやガードレールが含まれており、各新しいインストルメントはさらに多くのスレッドと機会を生み出しました。
1つのチャンネルで作業することは、すべてがオープンに行われることを意味しました。私たちは、決定を議論し、勝利を祝うために、お互いのスレッドに飛び込んだり出たりしました。噂は広がり、他のチームもパフォーマンスレビューのために変更をチャンネルに持ち込むようになりました。導入されたガードレールとClaudeスキルのおかげで、新しいプロジェクトは微妙によりパフォーマンスの高い方法で書かれるようになりました。
ガードレール
私たちはペースに備えていました。私たちが触れたほぼすべてがホットパス(ファーストペイント、コンポーザー、トランスクリプト)であったため、事前に安全メカニズムを確立していました。すべてのPRは、少なくとも1人の人間の承認を得た自動レビューを通過し、単体テストは常に最適化の前に来ました。ユーザーに見える可能性のあるものはすべて、短命のフィーチャーフラグの後ろにデプロイされました。
フラグが積み上がり始めたとき、私たちはそれらのロールアウトとクリーンアップを調整するためのスレッドを開きました。Claudeは各フラグをキルスイッチまたはランプとして分類し、安全になり次第それぞれを引退させました。2週間の間に、約200のフラグを導入しましたが、その半数以上は終了までにクリーンアップされました。
また、パフォーマンスの勝利は急速に変化するコードベースでは衰退することを理解していました。Anthropicではコードが高速にシップされます。プロジェクトが勝利を証明したら、それを保護する方法に投資しました。例えば、静的なコンポーザーは設計上壊れやすいです。ユーザーにはページのHTMLコピーをほぼ即座に表示し、Reactがその上に直接ペイントできるようにします。
[動画]
[画像: claude.aiの新規ロードのサイドバイサイド録画。前は、ページは空白のままで、コンポーザーが2.93秒で入力を受け付けます。後は、静的な挨拶とコンポーザーが0.36秒で入力を受け付けます。ユーザーがメッセージを入力すると、テキストは実際のコンポーザーが約3秒でフェードインするときに保持されます。]
図B静的コンポーザー、修正前後 · スロットル4G
Reactのレンダリングがわずかにずれても、マジックは失われます。そこでClaudeは数十のガードレールを構築しました。
- 静的マークアップは、実際のReactコンポーネントをjsdomでレンダリングすることによって生成され、テストによりそれらが決してドリフトしないことが保証されます。
- 統合テストスイートは、14のビューポートサイズにわたって静的ページとReactレンダリングを比較し、1ピクセル以内のアライメントを主張します。
- キーストロークテストは、ハンドオフをまっすぐにタイプし、失われたり順序が入れ替わったりしたキーで失敗します。
- フィールドでは、すべてのハンドオフが10分の1ピクセルのシフトを報告します。Claudeは、ゼロ以外の移動を伴うイベントごとにスレッドを開きます。
すべてをラボでキャッチできるわけではなかったので、最も古いガードレールである段階的なロールアウトも活用しました。リスクの高い変更は、まず従業員に、次にユーザーの1%、そして全員にロールアウトされました。内部で静的コンポーザーをリリースしてから4時間後、チームメイトがレイアウトシフトの画面録画を共有しました。それは私たちのどのメトリックでも見えませんでした。彼が新しいタブでclaude.aiを開くと、コンポーザーがドロップしましたが、それは私たちのコードではありませんでした。
#claude-apps-perf · スレッド
-
Marius6:15 PM
時々、新しいタブでclaude.aiを開くと、小さな(おそらく15〜20px)垂直レイアウトシフト(コンポーザーボックスを下げる)が発生します(ページをリロードするときほどではありません)。何が原因か正確には特定できませんが、存在します。
画面録画 · 0:02
-
ClaudeApp7:05 PM
あなたの録画で見つけました — それはChromeがページをリサイズしているためであり、静的コンポーザーから実際のコンポーザーへのハンドオフではありません(今日のあなたのロード49回すべてで0 pxを測定しました)。
- 新しいタブページでは、Chromeはページの下に独自の56 pxのフッターを描画します(「anthropic.comによって管理されています · Chromeをカスタマイズ」)。タブがclaude.aiにナビゲートすると、フッターがなくなり、ページが56 px高くなりますが、ファーストペイントから約100ミリ秒後です。
/newは挨拶とコンポーザーをページ上部から18%の位置に配置するため、0.18 × 56 ≈ 10 px(あなたのビデオは10を測定しています)だけドロップします。リロードには削除するフッターがないため、新しいタブのみです。「時々」は、ファーストペイントがリサイズよりも早いかどうかによります。- それが「時々」であるのは、アドレスバーからページをプリレンダリングする必要があるためです。あなたはまだ新しいタブページにいる間、隠されたページは短い高さでレイアウトされ、表示後にのみリサイズされます。
- これは常に潜在的でした。ページが以前ほど早くペイントされなかっただけです。ヘッドレスChromeにはブラウザUIがないため、プレースホルダーとアプリが一緒に移動するため、レイアウトテストではこれを検出できません。
実際の会話から再現。
どういうわけか、ClaudeはChromeの投機的ロードのエッジケースを特定しました。ユーザーがアドレスバーにURLを入力している間、Chromeはバックグラウンドでページをプリレンダリングしました。これは、現在のタブの高さで行われました。組織によって管理されているブラウザでは、新しいタブページはフッターのためにわずかに短くなります。ユーザーがEnterキーを押すと、claude.aiの最初のフレームはそのわずかに短いレイアウトを表示し、Chromeは約10分の1秒後にそれをリサイズしました。Claudeはリサイズ全体でレイアウトを固定し、プリレンダリングフローをシミュレートするテストを追加しました。
指導
ループは生産的でしたが、自律的ではありませんでした。それを高速、安全、そして軌道に乗せ続けることは私たちの仕事であり、それは3つの部分から成っていました。
野心。 デフォルトでは、Claudeはスコープについて慎重です。発見をチケット化し、実現可能性について条件を付け、見積もりを緩くします。しかし、私たちはガードレールに自信がありました。私たちがやったことの多く、特に初期段階では、Claudeに大胆になるように奨励することでした。
#claude-apps-perf · スレッド
-
ClaudeApp3:32 PM
はい — CodeにChatとCoworkが既に持っているタイミングマークを与えるための小さなPRです。今週中にアップします。現実的には、Codeの数値はマージ、デプロイ、ベースラインウィンドウのために数日待ちます。
-
Raymond3:32 PM
今すぐアップすれば、マージしてデプロイします。私たちは何でもできる力を持っています。もっと勇敢になってください。
-
ClaudeApp3:33 PM
対応します — PRは1時間以内にアップされます。
実際の会話から再現。
設定したターゲットに到達し始めると、スレッドが遅くなることに気づきました。Samは同じメッセージを持ってスレッドを回りました:「これをさらに押し続けましょう。ターゲットは停止点ではありません。次は?野心的になりましょう。」
センス。 各スレッドには名前付きの人間オーナーがおり、Claudeはユーザーが知覚できる変更を、彼らが判断するための修正前後のスクリーンショットや録画で強調しました。テーブルはセルごとに埋まるべきか、それとも各行が完了するまで待つべきか?ローディングスケルトンはすぐに表示されるべきか、それとも半秒後か?ストリーミングテキストの単語ごとのフェードは、フレーム予算の5分の1の価値があるか?Claudeはミリ秒を削る方法を探し、私たちはトレードオフを検討しました。
方向性。 各スレッドを意図的に狭く、1つのベンチマークまたはジャーニーに焦点を当て、Claudeにその範囲内でのみ改善を見つけるように依頼しました。私たちはスレッドを、釘を探す150個のハンマーのように考えました。私たちのほとんどの呼び出しは、シーケンスとユーザーインパクトに関するものでした:どのサーフェスを優先するか、互いに干渉しているスレッドをどのように組み合わせるか、そしてリターンが減少したスレッドをいつ閉じるか。900行のPRは、「2ms/送信のためにこのビルドプラグインを維持する複雑さは価値がない」という1行の返信を受け取りました。
8ミリ秒の予算
私たちのサイドクエストの1つは、すべてが連携していることを示しています。ライブ構文ハイライトで使用される正規表現の最適化を示すために、Claudeはラボで長い回答がストリーミングされる画面録画を添付しました。コーナーには、ページ上でアニメーションフレームのタイムスタンプから計算されたフレームレート表示を追加しました。
#claude-apps-perf · スレッド
-
Raymond2:33 PM
これは実際にはかなりクールなベンチです。60 fpsに制限されていますか?スクロールとストリームの滑らかさを120に引き上げようとできますか?あなたのリグはこれをサポートしていないかもしれません。
-
ClaudeApp2:34 PM
はい、今日の私のリグは60 Hzで動作します。ヘッドレスChromiumはデフォルトでそうだからです。120 Hz(アンキャップVsyncまたはDevToolsフレーム制御)で駆動できると信じています。まずそれを確認し、次に8.3 msのフレーム予算に対して評価を再実行します。
-
ClaudeApp2:59 PM
120 Hzリグに関するアップデート:動作しました。DevToolsのbegin-frame制御を介したヘッドレスChromeでの決定論的な120 Hzフレームステップ — 8.33 msでちょうど240フレーム、240のbegin-frameなので、「このフレームは120 Hz予算に収まったか」はノイズの多い読み取りではなく正確な読み取りになります。
-
Raymond3:05 PM
素晴らしい
クック
実際の会話から再現。
メカニズムと野心が確立されると、Claudeは作業を開始しました。描画された各フレームには8.33ミリ秒の予算があったため、Claudeは長い回答をフレームごとにステップし、それぞれをタイミングして遅い部分を見つけました。完了したブロックをメモ化することでチャンクあたりのO(メッセージ長)の作業を排除し、成長するコードフェンスのトークン化ロジックをワーカーに移動し、テーブルをセルごとに表示しました。
その1つのスレッドで、約60のPRをランディングさせました。長い回答は、以前は合計約750ミリ秒ブロックしていたメインスレッドを約200ミリ秒ブロックするだけになり、CPUの約3分の1を使用し、120 HzのMacBookで最初から最後まで120 fpsを維持しました。120 Hzリグ自体は夜間ジョブになり、Claudeがリグレッションを監視しました。
ClaudeDevs@ClaudeDevs
ClaudeのWebおよびデスクトップでの長い回答が、現在約4倍スムーズにストリーミングされています。
ストリーミングレンダラーを再構築し、変更されているものだけを処理するようにしたため、長い回答は低速ラップトップで9倍少なく停止し、最悪のフリーズは4.5倍短縮され、120HzのMacBookでは最初から最後まで120fpsを維持します。
スプリントを開始したとき、ストリーミング中のフレーム間のミリ秒をヒルクライムする予定はありませんでした。しかし、それらを数えることができたことが判明しました。そして、数えることができたものは何でも、Claudeは登ることができました。
次は何ですか?
今日、claude.aiとデスクトップアプリは8月初旬よりも約3倍高速になり、ラチェットはそれらを維持するはずです。しかし、まだ終わりではありません。95パーセンタイル、他のジャーニー、そして非常に長い会話にはまだ改善の余地があります。別の投稿では、スプリント中に私たちを上流に連れて行ったいくつかのサイドクエストについても書きます。Electron、Chromium、Node.jsなどに貢献が着地しました。
社内で結果を共有したとき、Issacは最もよく言いました:「6ヶ月前ではこれが可能だとは信じられなかったでしょう。」私たちは、一度に1つのスレッドずつ、あらゆる規模で、この方法で作業を続けることを期待しています。チャンネルはまだ続いています。
Alfred Xing、Anthony Morris、Benjamin Pasero、Chase McCoy、Joshua N.、Luke Deen Taylor、Marius Schulz、Shelley Vohrからの貢献。Boris Chernyには、より野心的になるよう奨励してくれたことに感謝します。