> ## Documentation Index
> Fetch the complete documentation index at: https://devdocs.xbox.com/llms.txt
> Use this file to discover all available pages before exploring further.

# WinHTTP の概要

> WinHTTP の概要

この記事では、Microsoft Game Development Kit (GDK) タイトルにおける [Windows HTTP Services (WinHTTP)](https://learn.microsoft.com/windows/desktop/winhttp/winhttp-start-page) 機能の使い方について説明します。WinHTTP は、PC および XBOX コンソールの Microsoft Game Development Kit (GDK) タイトルで利用できる低レベルの HTTP クライアント API です。通常の HTTP と WebSocket のサービス エンドポイントの作成に使用できます。

低レベル API であるため、セキュアで堅牢な通信をタイトルで実現するには考慮点や実装手順が多くなります。タイトルの実装が、[通信セキュリティのベスト プラクティス (NDA 記事)](/build/game-principles/security/communication-security-overview) すべてに従うことを推奨します。

## WinHTTP のバージョン差異

一般に、Microsoft Game Development Kit (GDK) タイトルは、Win32 アプリケーションで WinHTTP を扱うのと同じ方法で WinHTTP と対話します。

Microsoft Game Development Kit (GDK) タイトルの開発では、WinHTTP のフラット C/C++ API のみが利用可能です。つまり、HTTP 機能はこの HTTP クライアント API 上に構築する必要があります。

## XBOX コンソール プロジェクトへの WinHTTP の追加

コンソールでは、ソース ファイルに `#include <winhttp.h>` を記述してください。`Winhttp.lib` を直接リンクするのではなく、`XGamePlatform.lib` をリンクする必要があります。Microsoft Game Development Kit (GDK) タイトルで動作するのは `WINAPI_PARTITION_GAMES` API ファミリの API のみです。Windows PC では、これまでどおり `Winhttp.lib` をリンクしてください。

Microsoft Game Development Kit (GDK) タイトルに WinHTTP を統合する例については、[SimpleWinHttp サンプル](https://aka.ms/gdkdl) を参照してください。独自の WinHTTP 実装の出発点として堅実な基盤を提供し、シンプルな非同期 API 面を公開する `WinHttpManager` クラスも含まれています。

## ネットワーク初期化と WinHTTP

タイトルが初めて [WinHttpOpen](https://learn.microsoft.com/windows/desktop/api/winhttp/nf-winhttp-winhttpopen) を呼び出す前に、Microsoft Game Development Kit (GDK) タイトルはネットワーク スタックが初期化されていることを確認する必要があります。タイトルの起動プロセス中に `WinHttpOpen` を早すぎるタイミングで呼び出すと、`WinHttpOpen` またはその後の WinHTTP 呼び出しが非決定的に失敗またはクラッシュする可能性があります。ネットワークが初期化済みと宣言される前は、リクエストが成功したように見えて実際には失敗していたり、その逆になったりします。ネットワーク スタックがいつ初期化されるかを判定する方法の詳細は、[ネットワーク初期化](/build/console-features/networking/initialization-connectivity-networking#network-initialization) を参照してください。

## タイトルのサスペンド/レジュームと WinHTTP

タイトルがサスペンド通知を受け取ったら、すべての WinHTTP ハンドルを閉じる処理を開始する必要があります。WinHTTP ハンドルのクリーンアップは非同期です。そのため、すべてのリクエスト ハンドル、続いてすべての接続ハンドル、最後にすべてのセッション ハンドルの順に閉じてください。WinHTTP ハンドルのクリーンアップが非同期になっているのは、通知スレッドの安全性を確保するためです。非同期とはいえ、WinHTTP ハンドルのクリーンアップにかかる遅延は非常に短いため、サスペンド遅延の 1 秒のタイムアウトに簡単に収まります。

レジューム時には、タイトルは前述の「ネットワーク初期化と WinHTTP」で説明した手順に従い、WinHTTP の利用を続行する前にネットワークが再び準備完了状態に戻るのを待機してください。サスペンドとレジュームのイベント間には長い時間が経過している可能性があり、WinHTTP API が再び決定的に動作するまでネットワークが安定するのを待つ必要があります。

## メモリと同時実行の考慮事項

WinHTTP の非同期状態が正しく、かつメモリ予算内で動作するように、同時実行される WinHTTP リクエスト数は常に 8 未満に抑えてください。この制限は、XBOX サービス API や `XCurl` からの呼び出しを含む、タイトル ランタイム内のすべての同時操作に適用されます。

[WinSock のメモリに関する考慮事項](/build/console-features/networking/game-mesh/winsock-intro-networking#SocketMemory) の拡張として、データを受信する際は、カーネル モードのメモリ プールからユーザー モード プロセスにデータをできるだけ迅速に転送し、HTTP 処理で消費されるカーネル メモリを最小化するために、常に `WinHttpReadData` によりバッファーを保留状態にしておく (または `WinHttpQueryDataAvailable` 呼び出しのコールバックを待機している状態にしておく) 必要があります。

`WinHttpQueryHeaders` ゲッター関数は一時的なメモリ割り当てを必要とします。内部で使用する `lpdwBufferLength` パラメーターと同サイズのスクラッチ バッファーを割り当て (関数が戻る前に解放されます)。このため、システム メモリの過剰な使用によるシステム不安定を避けるためにも、`WINHTTP_NO_OUTPUT_BUFFER` のダブル呼び出しパターンを使用してスクラッチ バッファーのサイズを最小化し、`WinHttpQueryHeaders` の同時呼び出し数を制限してください。ヘッダーの既定の最大サイズは、WinHTTP オプションの `WINHTTP_OPTION_MAX_RESPONSE_HEADER_SIZE` で指定されているとおり 64 KB です。

## WinHttpOpen の考慮事項

### フラグ

[WinHttpOpen](https://learn.microsoft.com/windows/win32/api/winhttp/nf-winhttp-winhttpopen) には、次の表のフラグを渡す必要があります。

| パラメーター            | 値                                     |
| ----------------- | ------------------------------------- |
| `dwAccessType`    | `WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY` |
| `pszProxyW`       | `WINHTTP_NO_PROXY_NAME`               |
| `pszProxyBypassW` | `WINHTTP_NO_PROXY_BYPASS`             |
| `dwFlags`         | `WINHTTP_FLAG_SECURE_DEFAULTS`        |

`WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY`、`WINHTTP_NO_PROXY_NAME`、`WINHTTP_NO_PROXY_BYPASS` を組み合わせることで、Microsoft Game Development Kit (GDK) プラットフォームは [Fiddler](/build/console-features/networking/tools/fiddler-setup-networking) などのプロキシやその他のエッジ ケースのネットワーク環境を自動的に処理できます。

`WINHTTP_FLAG_SECURE_DEFAULTS` は、Microsoft Game Development Kit (GDK) タイトルが推奨のセキュア接続動作を設定することでセキュリティのベスト プラクティスに準拠しやすくするために設計された新しいフラグです。これは XBOX One コンソールで利用可能で、Windows PC では将来の Windows OS 更新プログラムで利用可能になる予定です。既存の Windows OS バージョンで `WINHTTP_FLAG_SECURE_DEFAULTS` を渡そうとすると、無効なパラメーター エラーになります。このフラグには重要な副作用があります。すなわち、`WINHTTP_FLAG_ASYNC` フラグを暗黙的に含むため、WinHTTP を強制的に非同期モードにします。このフラグがサポートされない Windows PC OS バージョンでは、WinHTTP 実装の他の部分の差を最小化するために、代わりに `WINHTTP_FLAG_ASYNC` を渡してください。

<Note>`WINHTTP_FLAG_SECURE_DEFAULTS` フラグは、`WinHttpOpenRequest` に渡される対応する `WINHTTP_FLAG_SECURE` フラグを必要とし、暗号化されていない HTTP リクエストをブロックします。内部デバッグやテスト用の開発キットでは、WinHTTP セッション ハンドルを作成する際に `WinHttpOpen` に `WINHTTP_FLAG_ASYNC` フラグを指定できます。これにより、`WinHttpOpenRequest` に `WINHTTP_FLAG_SECURE` フラグを指定しないことで、開発中は暗号化されていない HTTP リクエストを送信できます。それでも、RETAIL でタイトルが目にするリクエスト動作と一致させるため、非デバッグ トラフィックには `WINHTTP_FLAG_SECURE_DEFAULTS` で開いたセッション ハンドルを使用してください。</Note>

### WINHTTP\_OPTION\_SECURE\_PROTOCOLS

`WinHttpOpen` で新しいセッション ハンドルを作成した後は、[WinHttpSetOption](https://learn.microsoft.com/windows/win32/api/winhttp/nf-winhttp-winhttpsetoption) を `WINHTTP_OPTION_SECURE_PROTOCOLS` オプションで呼び出し、このセッション ハンドルが使用される URL について事前に [XNetworkingQuerySecurityInformationForUrlUtf16Async](/reference/networking/xnetworking/functions/xnetworkingquerysecurityinformationforurlutf16async) を呼び出して取得した対応する `XNetworkingSecurityInformation::enabledHttpSecurityProtocolFlags` を渡す必要があります。また、後で TLS/SSL ハンドシェイクを検証する際に使用するため、[XNetworkingSecurityInformation](/reference/networking/xnetworking/structs/xnetworkingsecurityinformation) 構造体をコンテキスト オブジェクトに保存しておいてください。

### セッション ハンドルのキャッシュ

`WinHttpOpen` で作成された HTTP セッション ハンドルはメモリ的に高価で、大きな起動コストがかかり、最初の HTTP リクエストを遅延させます。これらのコストを避けるため、タイトル内で HTTP セッション ハンドルをできる限りキャッシュすることを推奨します。

ただし、セッション ハンドル上で `WINHTTP_OPTION_SECURE_PROTOCOLS` オプションを変更することはできません。異なるセキュア プロトコル フラグごとに異なるセッション ハンドルを確保できるように、`XNetworkingSecurityInformation::enabledHttpSecurityProtocolFlags` の値と WinHTTP セッション ハンドルをマッピングしたキャッシュを保持してください。

タイトルが保持するキャッシュは、サスペンド通知でクリアし、レジューム時 (ネットワークが初期化されるのを待った後) にゼロから再構築する必要があります。

## WinHttpConnect の考慮事項

セッション ハンドルとは異なり、[WinHttpConnect](https://learn.microsoft.com/windows/win32/api/winhttp/nf-winhttp-winhttpconnect) で作成された接続ハンドルは決してキャッシュしないでください。新しいリクエストや再試行のたびに新しいハンドルを作成する必要があります。WinHTTP 接続ハンドルはその名前とは裏腹に、基盤となるサーバー Transmission Control Protocol (TCP) 接続とは無関係です。WinHTTP はセッション ハンドルで基盤となるサーバー接続のライフタイムを管理し、新しい接続ハンドルに対して可能な場合は既存のサーバー接続を自動的に再利用します。

### URL の正規化

WinHTTP は、すべての URL が a〜z、A〜Z、0〜9 の US-ASCII 文字に正規化されていることを期待します。正規化の詳細は [Uniform Resource Locators (URLs) in WinHTTP](https://learn.microsoft.com/windows/win32/winhttp/uniform-resource-locators--urls--in-winhttp) を参照してください。可能な限り、タイトルで使用する URL は正規化された形でハードコーディングすることを推奨します。この形式は、[WinHttpCrackUrl](https://learn.microsoft.com/windows/win32/api/winhttp/nf-winhttp-winhttpcrackurl) や [WinHttpCreateUrl](https://learn.microsoft.com/windows/win32/api/winhttp/nf-winhttp-winhttpcreateurl) を使って URL を動的に正規化する際に発生するメモリ割り当てやパフォーマンスの問題を回避できます。

### URL の分割

WinHTTP は、`WinHttpConnect` には null 終端のホスト名文字列を渡し、パスとオブジェクトは `WinHttpOpenRequest` に渡すことを要求します。タイトルは、ある場所では完全な URL (ホスト名とパスを連結したもの) を、別の場所ではホスト名またはパスのみを渡す必要があります。動的な連結や分割のために [WinHttpCrackUrl](https://learn.microsoft.com/windows/win32/api/winhttp/nf-winhttp-winhttpcrackurl) や [WinHttpCreateUrl](https://learn.microsoft.com/windows/win32/api/winhttp/nf-winhttp-winhttpcreateurl) を使う必要をなくすため、両方をタイトル内でハードコーディングすることを推奨します。

## WinHttpOpenRequest の考慮事項

WinHTTP 接続ハンドルと同様に、[WinHttpOpenRequest](https://learn.microsoft.com/windows/win32/api/winhttp/nf-winhttp-winhttpopenrequest) 関数で作成された WinHTTP リクエスト ハンドルも決してキャッシュしないでください。新しいリクエストや再試行のたびに新しいハンドルを作成する必要があります。

セキュリティのベスト プラクティスとして、タイトルは `WinHttpOpenRequest` 関数を呼び出す際、常に `dwFlags` パラメーターに `WINHTTP_FLAG_SECURE` フラグを渡してください。

## XBOX サービス トークンの取得と適用

Microsoft Game Development Kit (GDK) タイトルではトークンは自動挿入されません。代わりに、タイトルは Microsoft Game Development Kit (GDK) の [XUser](/reference/system/xuser/xuser_members) API を使って XBOX サービスの認証トークンと署名を取得する必要があります。タイトルがユーザーを取得した後は、各リクエストごとに [XUserGetTokenAndSignatureUtf16Async](/reference/system/xuser/functions/xusergettokenandsignatureutf16async) を呼び出してトークンと署名の文字列を取得します。これら 2 つの文字列は、`WinHttpAddRequestHeadersEx`、[WinHttpSendRequest](https://learn.microsoft.com/windows/desktop/api/winhttp/nf-winhttp-winhttpsendrequest)、または [WinHttpAddRequestHeaders](https://learn.microsoft.com/windows/desktop/api/winhttp/nf-winhttp-winhttpaddrequestheaders) の呼び出しでヘッダーとして渡します。

正しい署名を生成するには、[XUserGetTokenAndSignatureUtf16Async](/reference/system/xuser/functions/xusergettokenandsignatureutf16async) はタイトルにすべてのヘッダーと本文全体を渡すことを期待します。大きな本文を伴う `POST` または `PUT` の場合、タイトルはパートナー センターで構成した本文の一部を渡すことができます。詳細は [Web サービス (NDA トピック)](/services/xbox-services/fundamentals/s2s-auth-calls/custom-service-config/web-services/live-web-services-nav) を参照してください。現時点では、XBOX network はこの構成を取得するメカニズムを提供していません。クライアントは、値をハードコーディングするか、カスタムのタイトル固有エンドポイント経由で取得することが想定されています。

[XUserGetTokenAndSignatureUtf16Async](/reference/system/xuser/functions/xusergettokenandsignatureutf16async) は必要なキャッシュをすべて内部で処理しており、再試行を含む HTTP の試行ごとに呼び出す必要があります。任意の HTTP リクエストで 401 Unauthorized の HTTP レスポンス ステータス コードを受け取った場合、タイトルはリクエストを再試行し、XBOX サービス認証トークンを強制的に更新してください。この更新は、[XUserGetTokenAndSignatureUtf16Async](/reference/system/xuser/functions/xusergettokenandsignatureutf16async) で新しいトークンを取得する際に [XUserGetTokenAndSignatureOptions::ForceRefresh](/reference/system/xuser/enums/xusergettokenandsignatureoptions) 列挙値を渡すことで実現します。

タイトルが [XUserGetTokenAndSignatureUtf16Async](/reference/system/xuser/functions/xusergettokenandsignatureutf16async) の呼び出しから [XUserGetTokenAndSignatureUtf16Data](/reference/system/xuser/structs/xusergettokenandsignatureutf16data) を取得した後、タイトルは `XUserGetTokenAndSignatureUtf16Data::Token` と `XUserGetTokenAndSignatureUtf16Data::Signature` を WinHTTP に渡すための HTTP ヘッダーに変換する必要があります。Microsoft Game Development Kit (GDK) タイトル向けに複雑さを軽減する目的で、新しい WinHTTP API `WinHttpAddRequestHeadersEx` が追加されています。この新しい API の使用例を以下に示します。この新しい API は XBOX One コンソールで利用可能で、Windows PC では将来の Windows OS 更新プログラムで利用可能になる予定です。コンソール上では、余分な割り当てや文字列フォーマット変更を避けるため、`WinHttpAddRequestHeadersEx` の使用を推奨します。

```cpp theme={null}
HRESULT
AddTokenAndSignatureDataToHttpRequest(
    XUserGetTokenAndSignatureUtf16Data* userTokenAndSignatureData,
    HINTERNET requestHandle
    )
{
    WINHTTP_EXTENDED_HEADER winhttpHeader[2];
    winhttpHeader[0].pwszName = L"Authorization";
    winhttpHeader[0].pwszValue = userTokenAndSignatureData->token;
    winhttpHeader[1].pwszName = L"Signature";
    winhttpHeader[1].pwszValue = userTokenAndSignatureData->signature;
    return HRESULT_FROM_WIN32(WinHttpAddRequestHeadersEx(
        m_handshakeRequest,
        WINHTTP_ADDREQ_FLAG_ADD,
        WINHTTP_EXTENDED_HEADER_FLAG_UNICODE,
        0,
        tokenAndSignature->signatureCount ? 2 : 1,
        winhttpHeader));
}

```

<Note>デバイスまたはサインイン中のアカウントは、設定されているサンドボックスにアクセスできる必要があります。そうでない場合、`XUserGetTokenAndSignatureUtf16Data` は失敗します。</Note>

### XBOX Network Security Authorization List (NSAL) の使用

XBOX network は、クライアントがサービスとの間でセキュアで認証済みの接続を確立できるように NSAL を使用しています。タイトルはパートナー センターの構成の一部として NSAL の内容を管理します。詳細は [パートナー センターでの Web サービス構成 (NDA トピック)](/services/xbox-services/fundamentals/s2s-auth-calls/custom-service-config/web-services/live-web-services) を参照してください。NSAL 構成は各タイトルに自動的にダウンロードされます。これは、適切な XBOX サービス トークンの生成と、タイトル固有のエンドポイントに対する証明書ピニングの両方に使用されます。}

## WinHTTP 非同期状態マシンの考慮事項

WinHTTP の非同期状態マシンは、コンソールでも Windows PC でも同じです。1 つまたは複数の通知に対してコールバック関数を登録するには、[WinHttpSetStatusCallback](https://learn.microsoft.com/windows/win32/api/winhttp/nf-winhttp-winhttpsetstatuscallback) 関数を使用します。WinHTTP は比較的冗長で動作が可視化されているため、デバッグ目的では `dwNotificationFlags` パラメーターに `WINHTTP_CALLBACK_FLAG_ALL_NOTIFICATIONS` フラグを使用することを推奨します。ほとんどの通知は特に処理を必要としませんが、データをログに残しておくと問題の根本原因の発見に役立ちます。

WinHTTP は通知のために単一のスレッドを使用します。タイトルは、プロセス内のすべての HTTP リクエストの進行を止めないよう、通知関数のいずれもブロックしないようにしてください。処理されない通知はカーネル モードのメモリを増加させ、クラッシュにつながる可能性もあります。

WinHTTP は送受信バッファーをコピーしないため、対応する完了コールバックが返るまでそれらのバッファーを割り当て済みのまま保持する必要があります。[WinHttpSendRequest](https://learn.microsoft.com/windows/win32/api/winhttp/nf-winhttp-winhttpsendrequest) を呼び出してから、対応する `WINHTTP_CALLBACK_STATUS_SENDREQUEST_COMPLETE` 通知を受信するまで、送信バッファーは有効なまま保持してください。同様に、[WinHttpReadData](https://learn.microsoft.com/windows/win32/api/winhttp/nf-winhttp-winhttpreaddata) を呼び出すたびに、対応する `WINHTTP_CALLBACK_STATUS_READ_COMPLETE` 通知を受信するまで受信バッファーを有効なまま保持してください。また、スタック枯渇につながる再帰の問題を避けるため、受信バッファーは少なくとも 8 KB 以上のサイズにすることを推奨します。

タイトルは、`WinHttpQueryDataAvailable`/`WinHttpReadData` の非同期サイクルを継続し、WinHTTP コールバックを長時間ブロックしないことで、WinHTTP バッファーが正しく空にされることを確認してください。

### Transport Layer Security (TLS)/Secure Sockets Layer (SSL) ハンドシェイクの検証

セキュリティのベスト プラクティスとして、タイトルは TLS/SSL ハンドシェイクを検証し、TLS 1.2 のみを使用してください。

追加の検証は `WINHTTP_CALLBACK_STATUS_SENDING_REQUEST` 通知内で実行します。この通知内で、[XNetworkingVerifyServerCertificate](/reference/networking/xnetworking/functions/xnetworkingverifyservercertificate) 関数を呼び出し、事前に対応する [XNetworkingQuerySecurityInformationForUrlUtf16Async](/reference/networking/xnetworking/functions/xnetworkingquerysecurityinformationforurlutf16async) 呼び出しから取得した [XNetworkingSecurityInformation](/reference/networking/xnetworking/structs/xnetworkingsecurityinformation) 構造体を渡す必要があります。この関数は、証明書チェーンが無効な場合に失敗します。侵害されたサーバーとの間でデータが転送されないようにするために、コールバックが完了する前に *即座に* WinHTTP ハンドルを閉じてください。

証明書チェーンの検証に加え、[XNetworkingVerifyServerCertificate](/reference/networking/xnetworking/functions/xnetworkingverifyservercertificate) 関数はコンソール上での Fiddler 機能に必須です。

## WinHTTP のデバッグ

[Fiddler](/build/console-features/networking/tools/fiddler-setup-networking) は WinHTTP のトラフィックを表示・デバッグするのに有用なツールです。Fiddler がタイトルのトラフィックをキャプチャできるようにするには、`WinHttpOpen` に `WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY`、`WINHTTP_NO_PROXY_NAME`、`WINHTTP_NO_PROXY_BYPASS` フラグを渡す必要があります。また、`WINHTTP_CALLBACK_STATUS_SENDING_REQUEST` 通知コールバック内で [XNetworkingVerifyServerCertificate](/reference/networking/xnetworking/functions/xnetworkingverifyservercertificate) を呼び出す必要もあります。

<Note>HTTP Monitor は Microsoft Game Development Kit (GDK) タイトルでは動作しません。</Note>

## リファレンス API ドキュメント

* [Xuser (API 一覧)](/reference/system/xuser/xuser_members)
  * 関数
    * [XUserGetTokenAndSignatureUtf16Async](/reference/system/xuser/functions/xusergettokenandsignatureutf16async)
  * 構造体
    * [XUserGetTokenAndSignatureUtf16Data](/reference/system/xuser/structs/xusergettokenandsignatureutf16data)
* [xnetworking (API 一覧)](/reference/networking/xnetworking/xnetworking_members)
  * 関数
    * [XNetworkingQuerySecurityInformationForUrlUtf16Async](/reference/networking/xnetworking/functions/xnetworkingquerysecurityinformationforurlutf16async)
    * [XNetworkingVerifyServerCertificate](/reference/networking/xnetworking/functions/xnetworkingverifyservercertificate)
  * 構造体
    * [XNetworkingSecurityInformation](/reference/networking/xnetworking/structs/xnetworkingsecurityinformation)

## 関連項目

[Windows HTTP Services (WinHTTP)](https://learn.microsoft.com/windows/desktop/winhttp/winhttp-start-page)

[XSAPI C の概要 (セキュア リンク)](https://developer.microsoft.com/games/xbox/docs/gdk/atoc-xsapi-c)

[XUser](/reference/system/xuser/xuser_members)

[パートナー センターでの Web サービス構成 (NDA 記事)](/services/xbox-services/fundamentals/s2s-auth-calls/custom-service-config/web-services/live-web-services)

[XBOX One コンソール上の Fiddler](/build/console-features/networking/tools/fiddler-setup-networking)

[通信セキュリティのベスト プラクティスの概要 (NDA 記事)](/build/game-principles/security/communication-security-overview)


## Related topics

- [Web リクエスト](/ja-jp/build/console-features/networking/web-requests/web-requests-toc.md)
- [XNetworkingQuerySecurityInformationForUrlUtf16Async](/ja-jp/reference/networking/xnetworking/functions/xnetworkingquerysecurityinformationforurlutf16async.md)
- [XNetworkingSecurityInformation](/ja-jp/reference/networking/xnetworking/structs/xnetworkingsecurityinformation.md)
- [XUserGetTokenAndSignatureUtf16Data](/ja-jp/reference/system/xuser/structs/xusergettokenandsignatureutf16data.md)
- [XNetworkingVerifyServerCertificate](/ja-jp/reference/networking/xnetworking/functions/xnetworkingverifyservercertificate.md)
