イベントリスナーはどのように機能しますか?


125

今日のUnityに関する講義の1つで、ユーザーがボタンを押した場合にすべてのフレームをチェックしてプレーヤーの位置を更新することについて説明しました。誰かがこれは非効率的だと言ったので、代わりにイベントリスナーを使うべきです。

私の質問は、プログラミング言語、またはそれが適用される状況に関係なく、イベントリスナーはどのように機能するのですか?

私の直感では、イベントリスナーはイベントが発生したかどうかを常にチェックすると想定します。つまり、私のシナリオでは、イベントが発生した場合はすべてのフレームをチェックすることと同じです。

クラスでの議論に基づいて、イベントリスナーは異なる方法で動作するようです。

イベントリスナーはどのように機能しますか?


34
イベントリスナはまったくチェックしません。「リスニング」しているイベントが発生したときに呼び出されます。
ロバートハーベイ

13
はい、しかしそれはどのように「リッスン」しますか、それは常にチェックしていませんか?
ゲイリーホリデー

28
いや。「イベントリスナー」は、おそらく不適切な単語の選択です。実際にはまったく「リッスン」しません。イベントリスナーが行うことは、他のメソッドと同様に、イベントが発生したときにイベントによって呼び出されるのを待つことだけです。この方法で呼び出されるまで、何もしません。
ロバートハーベイ

28
ボタンが押されているかどうかを確認するたびに、クロックサイクルがかかります。イベントハンドラー(リスナー)は、ボタンが実際に押されたときにのみコストがかかります。
ロバートハーベイ

45
@RobertHarvey-必ずしもそうではありませんが、「リスナー」は依然として低レベルでの一定のポーリングを必要とします。独自のコードレイヤーからハードウェアの割り込みなどに複雑さを押し下げるだけです。はい、これは通常、より効率的ですが、リスニングがポーリングよりも優れているためではなく、C#やユーザーとハードウェア間の15層の抽象化からのポーリングよりも低いレベルでのポーリングがより効率的であるためです。
DavorŽdralo

回答:


140

提供したポーリングの例(ボタンがフレームごとにチェックされる)とは異なり、イベントリスナーはボタンがまったく押されたかどうかをチェックしません。代わりに、ボタンが押されたときに呼び出されます。

おそらく「イベントリスナー」という言葉があなたを投げかけているのでしょう。この用語は、「リスナー」が積極的に何かを聞いていることを示唆していますが、実際にはまったく何もしていません。「リスナー」は、イベントにサブスクライブされる単なる関数またはメソッドです。イベントが発生すると、リスナーメソッド(「イベントハンドラー」)が呼び出されます。

イベントパターンの利点は、ボタンが実際に押されるまで費用がかからないことです。イベントは、「ハードウェア割り込み」と呼ばれるものから発生するため、監視されずにこの方法で処理できます。これは、実行中のコードを一時的に無効にしてイベントを発生させます。

一部のUIおよびゲームフレームワークは、「メッセージループ」と呼ばれるものを使用します。これは、後の(通常は短い)期間に実行するイベントをキューに入れますが、そもそもそのイベントをメッセージループに入れるにはハードウェア割り込みが必要です。


54
ボタンがプッシュされるまでコストがかからない理由は、ボタンが「特別」であり、コンピューターに割り込みやOSが使用できるその他の特別な機能があり、ユーザースペースアプリケーションに抽象化されているためです。
-whatsisname

46
@whatsisnameは内部では非常に深いケースですが、実際にはゲームエンジンは割り込みで動作していない可能性がありますが、実際にはループ内でイベントソースをポーリングしています。このポーリングは集中化および最適化されているため、イベントリスナーを追加してポーリングや複雑さが増すことはありません。
gntskn

7
@PieterGeerkens gntsknは、ゲームエンジンループの一部として、未処理のイベントをチェックするステップがあることを意味すると思います。イベントは、他のすべてのループごとのアクティビティとともに、各ループ中に処理されます。イベントをチェックするための独立したループはありません。
ジョシュアテイラー

2
@Voo:この投稿でこのレベルの詳細に立ち入らない理由は他にもあります。
ロバートハーヴェイ

2
@Voo:キーボードの物理キーやマウスボタンのようなボタンについて話しています。
-whatsisname

52

Webページ(情報の転送を開始する場所)を際限なく更新するのではなく、電子メールニュースレターサブスクリプションに似たイベントリスナ(更新を受信するために自分で登録し、その送信は後で送信者によって開始されます)。

イベントシステムは、サブスクライバーのリストを管理するイベントオブジェクトを使用して実装されます。関心のあるオブジェクト(サブスクライバーリスナーデリゲートなど)は、イベントに自分自身をサブスクライブするメソッドを呼び出すことで、イベントを通知するために自分自身をサブスクライブできます。イベントがされるたびに解雇(専門用語でも含めることができますと呼ばれトリガ呼び出され実行など)、それは彼らが理解する必要が文脈な情報を渡して、イベントを知らせるために、加入者のそれぞれに適切なメソッドを呼び出しますどうした。


38

短く不十分な答えは、アプリケーションがシグナル(イベント)を受信し、その時点でのみルーチンが呼び出されるということです。

長い説明はもう少し複雑です。

クライアントイベントはどこから来ますか?

最新の各アプリケーション†には、イベントを受け取るべき正しいコンポーネントにイベントをディスパッチする、通常は半隠された内部の「イベントループ」があります。たとえば、現在のマウス座標で表面が見えるボタンに「クリック」イベントが送信されます。これは最も単純なレベルです。実際には、OSはいくつかのイベントとコンポーネントがメッセージを直接受信するため、このディスパッチの多くを実行します。

アプリケーションイベントはどこから来ますか?

オペレーティングシステムは、イベントが発生するとディスパッチします。彼らは、彼ら自身のドライバーから通知されることにより、反応的にそうします。

ドライバーはどのようにイベントを生成しますか?

私は専門家ではありませんが、確かにいくつかはCPU割り込みを使用します。新しいデータが利用可能になると、それらが制御するハードウェアがCPUのピンを上げます。CPUはドライバーを起動し、ドライバーは着信データを処理し、最終的にディスパッチするイベント(のキュー)を生成し、OSに制御を返します。

ご覧のとおり、アプリケーションは実際には常に実行されているわけではありません。これは、イベントが発生するとOS(sorta)によって起動される一連のプロシージャですが、それ以外は何もしません。


注目すべき例外があります。たとえば、1回限りのゲームで、物事が異なる場合があります


10
この回答は、ブラウザのマウスクリックイベントにポーリングが含まれない理由を説明しています。ハードウェアは割り込みを生成します=>ドライバはOSイベントに解決します=>ブラウザはDOMイベントに解決します=> JSエンジンはそのイベントのリスナーを実行します
ティボス

@Tibosは、キーボードイベント、タイマーイベント、ペイントイベントなどにも適用されます
。– Sklivvz

19

用語

  • イベント:発生する可能性のある種類。

  • イベント発生:イベントの特定の発生。イベントが発生します。

  • イベントリスナー:イベントの発生を監視するもの。

  • イベントハンドラー:イベントリスナーがイベントの発生を検出したときに発生するもの。

  • イベントサブスクライバー:イベントハンドラーが呼び出すことになっている応答。

これらの定義は実装に依存しないため、さまざまな方法で実装できます。

これらの用語の一部は、ユーザーがそれらを区別する必要がないことが多いため、一般に同義語と間違えられます。

一般的なシナリオ

  1. プログラミングロジックイベント。

    • イベントには、いくつかのメソッドが呼び出されたときです。

    • イベントの焼成は、そのメソッドへの特定のコールです。

    • イベントリスナーは、イベントハンドラを呼び出す各イベントの発火に呼ばれていますイベントメソッドでフックです。

    • イベントハンドラは、イベントの加入者のコレクションを呼び出します。

    • イベントの加入者(複数)は、システムがイベントの発生に応答して発生するあらゆる手段アクション(複数可)を実行します。

  2. 外部イベント。

    • このイベントは、オブザーバブルから推測できる外部の出来事です。

    • イベントの発火は、その外部の出来事が発生したと認識することができたときです。

    • イベントリスナーは、何らかの形で、多くの場合、ポーリングによって、イベントの発射を検出し、観察(s)は、それが発火イベントを検出すると、イベントハンドラが呼び出されます。

    • イベントハンドラは、イベントの加入者のコレクションを呼び出します。

    • イベントの加入者(複数)は、システムがイベントの発生に応答して発生するあらゆる手段アクション(複数可)を実行します。

ポーリングとイベントの発生メカニズムへのフックの挿入

他の人が言ったポイントは、ポーリングはしばしば必要ないということです。これは、イベントがシステムレベルで発生する場合にイベントを実行する最も効率的な方法であるイベントハンドラーを自動的に呼び出すことにより、イベントリスナーを実装できるためです。

同様に、郵便局員がドアをノックしてメールを直接あなたに渡す場合、毎日メールのメールボックスをチェックする必要はありません。

ただし、イベントリスナーはポーリングによっても機能します。ポーリングでは、必ずしも特定の値またはその他の観測可能な値をチェックする必要はありません。より複雑になる可能性があります。しかし、全体として、ポーリングのポイントは、何らかのイベントが発生して応答できるようになるタイミングを推測することです。

たとえると、郵便局員が郵便物を入れただけで毎日メールボックスをチェックする必要があります。郵便局員にドアをノックするように指示できれば、このポーリング作業を行う必要はありませんが、それは多くの場合不可能です。

イベントロジックの連鎖

多くのプログラミング言語では、キーボードのキーが押されたとき、または特定の時間に呼び出されるイベントを作成できます。これらは外部イベントですが、ポーリングする必要はありません。どうして?

オペレーティングシステムがあなたのためにポーリングしているからです。たとえば、Windowsはキーボードの状態変化などをチェックし、それを検出すると、イベントサブスクライバーを呼び出します。したがって、キーボードプレスイベントをサブスクライブすると、実際には、ポーリングするイベントのサブスクライバーであるイベントをサブスクライブします。

たとえば、あなたがアパートに住んでいて、郵便局員が郵便物を共同の郵便物受け取りエリアに落とすとします。次に、オペレーティングシステムに似た作業者が全員のメールを確認し、何かを受け取った人のアパートにメールを配信します。これにより、他のすべての人がメール受信エリアをポーリングする必要がなくなります。


私の直感では、イベントリスナーはイベントが発生したかどうかを常にチェックすると想定します。つまり、私のシナリオでは、イベントが発生した場合はすべてのフレームをチェックすることと同じです。

クラスでの議論に基づいて、イベントリスナーは異なる方法で動作するようです。

イベントリスナーはどのように機能しますか?

ご想像のとおり、イベントポーリングを通じて機能します。また、イベントが何らかの形で外部の出来事に関連している場合(キーボードのキーが押されるなど)、ある時点でポーリングを行う必要があります。

また、イベントが必ずしもポーリングを必要としないことも事実です。たとえば、ボタンが押されたときにイベントが発生する場合、そのボタンのイベントリスナーは、マウスクリックがボタンを押したと判断したときにGUIフレームワークが呼び出すメソッドです。この場合、マウスクリックを検出するためにポーリングを行う必要がありましたが、マウスリスナは、イベントチェーンを通じてプリミティブポーリングメカニズムに接続される、より受動的な要素です。

更新:低レベルのハードウェアポーリングについて

USBデバイスやその他の最新の通信プロトコルには、相互作用のためのかなり魅力的なネットワークのようなプロトコルのセットがあり、キーボードやマウスを含むI / Oデバイスがアドホックトポロジに関与できることがわかります

興味深いことに、「割り込み」はかなり必須の同期的なものであるため、アドホックネットワーキングトポロジを処理しません。これを修正するために、「割り込み」は割り込みトランザクション(USBのコンテキスト)またはメッセージ信号割り込み(PCIのコンテキスト)と呼ばれる非同期の高優先度パケットに一般化されました。このプロトコルは、USB仕様で説明されています。

ここに画像の説明を入力してください

- 「図8-31バルク/コントロール/インタラプトOUTトランザクションホストステートマシンで」『ユニバーサルシリアルバス仕様、リビジョン2.0』、印刷されたページ-222; PDFページ250(2000-04-27)

要点は、I / Oデバイスと通信コンポーネント(USBハブなど)が基本的にネットワークデバイスのように振る舞うということです。そのため、ポートをポーリングする必要があるメッセージなどを送信します。これにより、専用のハードウェアラインの必要性が軽減されます。

Windowsのようなオペレーティングシステムはで説明したように、たとえば、ポーリングプロセス自体、取り扱うように見えるため、MSDNのドキュメントUSB_ENDPOINT_DESCRIPTOR割り込み/アイソクロナスのメッセージの頻度を、WindowsのポーリングUSBホストコントローラを制御する方法について説明します:

bInterval値は、割り込みとアイソクロナスエンドポイントのポーリング間隔が含まれています。他のタイプのエンドポイントの場合、この値は無視する必要があります。この値は、ファームウェアでのデバイスの構成を反映しています。ドライバーは変更できません。

ポーリング間隔は、デバイスの速度とホストコントローラーの種類と共に、ドライバーが割り込みまたはアイソクロナス転送を開始する頻度を決定します。の値はbInterval、一定の時間を表すものではありません。これは相対的な値であり、実際のポーリング頻度は、デバイスとUSBホストコントローラーが低速、フル、または高速で動作するかどうかにも依存します。

- 「USB_ENDPOINT_DESCRIPTOR構造」、Microsoft、ハードウェアデベロッパーセンター

DisplayPortのような新しいモニター接続プロトコルも同じように見えます:

マルチストリームトランスポート(MST)

  • DisplayPort Ver.1.2に追加されたMST(マルチストリームトランスポート)

    • Ver.1.1aではSST(Single-Stream Transport)のみが利用可能でした
  • MSTは単一のコネクタを介して複数のA / Vストリームを転送します

    • 最大63ストリーム。「レーンごとのストリーム」ではありません

      • 転送されたストリーム間で同期性は想定されていません。1つのストリームはブランキング期間にあるかもしれませんが、他のストリームはそうではありません
    • 接続指向のトランスポート

      • ストリーム送信の開始前に、AUX CHを介したメッセージトランザクションを介して確立された、ストリームソースからターゲットストリームシンクへのパス

      • 残りのストリームに影響を与えないストリームの追加/削除

ここに画像の説明を入力してください

-Slide から14 "DisplayPortTM Ver.1.2の概要"(2010-12-06)

この抽象化により、1つの接続から3つのモニターを実行するなど、いくつかの便利な機能が可能になります。

DisplayPort Multi-Stream Transportを使用すると、3つ以上のデバイスを接続できますが、逆に「消費者」指向の構成ではなく、単一の出力ポートから複数のディスプレイを同時に駆動できます。

- "DisplayPort"、ウィキペディア

概念的には、これを取り除くポイントは、ポーリングメカニズムにより、より一般化されたシリアル通信が可能になることです。これは、より一般的な機能が必要な場合に最適です。そのため、ハードウェアとOSは論理システムに対して多くのポーリングを行います。その後、イベントをサブスクライブするコンシューマーは、独自のポーリング/メッセージ受け渡しプロトコルを作成することなく、下位レベルのシステムによって処理されるイベントの詳細を楽しむことができます。

最終的に、キーを押すなどのイベントは、ソフトウェアレベルの命令型イベント発行メカニズムに到達する前に、かなり興味深い一連のイベントを通過するようです。


最後の段落については、一般に低レベルでのポーリングは行われず、オペレーティングシステムは周辺機器によってトリガーされるハードウェア割り込みに反応します。通常、コンピューターには多数の接続デバイス(マウス、キーボード、ディスクドライブ、ネットワークカード)があり、それらすべてをポーリングするのは非常に非効率的です。
バーマー

ただし、メール配信とのアナロジーは、より高いレベルのアクティビティを説明する方法とまったく同じです。
バーマー

1
@Barmar Yaは、デバイスがUSB接続に移行したときに、割り込みを直接生成する方法(PS / 2キーボードのように)からポーリングを必要とする方法(USBキーボードのように)について多くの話があり、いくつかのソースは主張していますポーリングはCPUによって行われます。しかし、他のソースは、ポーリングをCPUの割り込みに変換する専用のコントローラーで行われたと主張しています。
ナット

@Barmarあなたはたまたま正しいことを知っていますか?CPUが他の方法よりもポーリングを行うと主張するソースが多分あるでしょうが、専用のコントローラーがより理にかなっているようです。つまり、Arduinoやその他の組み込みデバイスはポーリングを実行するためにCPUを必要とする傾向があると思いますが、x86タイプのデバイスについては知らないのです。
ナット

1
この答えを更新できるように誰かが確認できる場合、最新のI / Oデバイス、たとえばUSBで接続されたデバイスは、CPUの制御をバイパスしてメモリに直接書き込むと思います(これが高速/効率的でセキュリティが高い理由です)時々危険)。次に、最新のOSがメモリをポーリングして新しいメッセージをチェックする必要があります。
ナット

8

プルvsプッシュ

イベントが発生したか、特定の状態に到達したかを確認するには、2つの主な戦略があります。たとえば、重要な配信を待つことを想像してください。

  • プル:10分ごとに、メールボックスに移動して、配信されたかどうかを確認し、
  • プッシュ:配達をするときに配達人に電話するように伝えます。

プル(もポーリングと呼ばれる)のアプローチは単純です:あなたは特別な機能なしでそれを実装することができます。一方で、何も表示せずに余分なチェックを行うリスクがあるため、多くの場合効率が低下します。

一方、プッシュアプローチの方が一般的に効率的です。コードは、実行する必要があるときにのみ実行されます。一方、リスナー/オブザーバー/コールバックを登録するためのメカニズムが存在する必要があります1

1 残念ながら、私の郵便配達員には通常このようなメカニズムがありません。


1

具体的な統一について-プレイヤーの入力を確認する方法は、フレームごとにポーリングする以外にありません。イベントリスナを作成するには、ポーリングを行うために「イベントシステム」や「イベントマネージャ」などのオブジェクトが必要なので、問題を別のクラスにプッシュするだけです。

確かに、イベントマネージャーを取得すると、フレームごとに入力をポーリングするクラスが1つだけになりますが、これは明らかなパフォーマンス上の利点を与えません。設計(たとえば、リスナーが何人いるか、プレーヤーが入力を使用する頻度など)は、実際にはよりコストがかかる可能性があります。

別にこのすべてから、黄金のルールを覚えている- 時期尚早の最適化は諸悪の根源である。このような小さなスクリプトの最適化が完全に重要でないことを、多くの場合、各フレームをレンダリングするプロセスはあまりコストのビデオゲーム、では特にそうです、


中央イベントループは最適化とは見なされませんが、ポーリングがコードベース全体に拡散するのではなく、より読みやすく、わかりやすいコードを記述することです。また、「合成」イベントと、ゲームエンジンのポーリングから発生しないイベントも許可します。
ブラックジャック

@BlackJack私は同意し、通常は自分でこの方法でコーディングしますが、OPはパフォーマンスについて尋ねました。ところで、Unityには、ほぼすべての場所で静的関数を使用するなど、このように驚くほど多くの疑わしいコード設計の決定があります。
知らん

1

OS /フレームワークで、ボタンプッシュ、タイマーオーバーフロー、メッセージ到着などのイベントを処理するサポートがない場合は、とにかく(下に)ポーリングを使用してこのイベントリスナーパターンを実装する必要があります。

ただし、すぐにパフォーマンス上のメリットが得られないという理由だけで、このデザインパターンから離れないでください。イベント処理の基礎となるサポートがあるかどうかに関係なく、使用する必要がある理由を以下に示します。

  1. コードはよりクリーンで、より分離されているようです(正しく実装されている場合は、もちろん)
  2. イベントハンドラに基づいたコードは、変更をより適切に反映します(通常、イベントハンドラの一部のみを変更するため)
  3. アンダーレイイベントサポートを使用してプラットフォームに移動した場合、既存のイベントハンドラを再利用して、ポーリングコードを取り除くことができます。

結論-議論に参加できたことは幸運であり、ポーリングに代わる方法を学びました。この概念を実際に適用する機会を探してください。コードがどれほどエレガントであるかに感謝します。


1

ほとんどのイベントループは、オペレーティングシステムによって提供されるポーリング多重化プリミティブの上に構築されます。Linuxでは、多くの場合、そのプリミティブはpoll(2)システムコールです(ただし、古いselectものでもかまいません)。GUIアプリケーションでは、ディスプレイサーバーXorgWaylandなど)はアプリケーションと通信しています(socket(7)またはpipe(7)を介して)。X Window System Protocols and Architectureについてもお読みください。

このようなポーリングプリミティブは効率的です。カーネルは実際には、何らかの入力が行われたときにプロセスを起動します(そして、いくつかの割り込みが処理されます)。

具体的には、ウィジェットツールキットライブラリはディスプレイサーバーと通信してメッセージを待機し、これらのメッセージをウィジェットにディスパッチします。QtGTKなどのツールキットライブラリは非常に複雑です(数百万行のソースコード)。キーボードとマウスは、ディスプレイサーバープロセス(このような入力をクライアントアプリケーションに送信されるイベントメッセージに変換する)によってのみ処理されます。

(私は単純化しています;実際にはもっと複雑です)


1

純粋にポーリングベースのシステムでは、特定のアクションがいつ発生するかを知りたいサブシステムは、アクションが発生するたびにコードを実行する必要があります。何らかの不必要に固有のイベントが発生してから10ミリ秒以内に反応する必要があるサブシステムが多数ある場合、それらはすべて、イベントが発生したかどうかを少なくとも100回/秒で確認する必要があります。これらのサブシステムが異なるスレッド(さらに悪いことにプロセス)プロセスにある場合、そのようなすべてのスレッドまたはプロセスを毎秒100xに切り替える必要があります。

アプリケーションが監視するものの多くがかなり類似している場合、多くのことを監視し、それらのいずれかが変更されたかどうかを監視できる、1つの監視サブシステム(テーブル駆動型)を一元化する方が効率的です。たとえば、32個のスイッチがある場合、プラットフォームには32個のスイッチすべてを一度に1つの単語に読み込む機能があり、モニターコードがポーリング間でスイッチが変更されたかどうかをチェックできるようにします。どのコードがそれらに興味があるのか​​心配します。

何かが変化したときに通知を必要とするサブシステムが多数ある場合、専用の監視サブシステムは、関心のあるイベントが発生したときに他のサブシステムに通知する方が、各サブシステムが独自のイベントをポーリングするよりも効率的です。ただし、イベントに誰も関心がない場合に専用の監視サブシステムをセットアップすると、リソースが無駄になります。イベントに関心のあるサブシステムが少数しかない場合、関心のあるイベントを監視させるコストは、汎用の専用監視サブシステムをセットアップするコストよりも低くなる可能性がありますが、損益分岐点ポイントはプラットフォームによって大きく異なります。


0

イベントリスナーは、メッセージを待っている耳のようなものです。イベントが発生すると、イベントリスナーとして選択されたサブルーチンはイベント引数を使用して動作します。

常に2つの重要なデータがあります。イベントが発生する瞬間と、このイベントが発生するオブジェクトです。他の議論は何が起こったかについてのより多くのデータです。

イベントリスナーは、発生する反応を指定します。


0

イベントリスナーは、次のパブリッシュ/サブスクライブパターンを(加入者として)

最も単純な形式では、発行オブジェクトは、発行が必要なときに実行されるサブスクライバーの指示のリストを保持します。

subscribe(x)xには、イベントハンドラーがイベントを処理するためにどのように設計されているかに依存する、ある種のメソッドがあります。subscribe(x)が呼び出されると、xがサブスクライバーの命令/参照のパブリッシャーリストに追加されます。

発行者は、イベントを処理するためのロジックのすべて、一部、またはまったくを含まない場合があります。イベントが発生したときに、指定されたロジックで通知/変換するために、サブスクライバーへの参照が必要になる場合があります。ロジックを含まず、イベントを処理できるサブスクライバーオブジェクト(メソッド/イベントリスナー)が必要な場合があります。ほとんどの場合、両方の混合物が含まれます。

イベントが発生すると、パブリッシャーは、サブスクライバーの指示/参照のリスト内の各アイテムに対してロジックを繰り返し実行します。

イベントハンドラがどれほど複雑に見えても、そのコアはこの単純なパターンに従います。

イベントリスナーの例では、イベントハンドラーのsubscribe()メソッドにメソッド/関数/命令/イベントリスナーを提供します。イベントハンドラは、メソッドをサブスクライバコールバックのリストに追加します。イベントが発生すると、イベントハンドラーはそのリストを反復処理し、各コールバックを実行します。

実際の例では、Stack Exchangeのニュースレターを購読すると、サブスクライバーのデータベーステーブルにプロファイルへの参照が追加されます。ニュースレターを公開するときは、参照を使用してニュースレターのテンプレートを作成し、メールに送信します。この場合、xは単にあなたへの参照であり、パブリッシャーにはすべてのサブスクライバーに使用される一連の内部命令があります。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.