[インデックス 12097] ファイルの概要
このコミットは、Go言語の標準ライブラリである net
パッケージ内の tcpsock_posix.go
ファイルに対する変更です。具体的には、TCP接続の確立処理において、selfConnect
と呼ばれる稀なバグを早期に検出するための診断コードが追加されています。この変更は、Goのネットワークスタックの堅牢性を向上させることを目的としています。
コミット
commit 2155a0408eb50ce8ae47d5b3b53c3363498cd716
Author: Rob Pike <r@golang.org>
Date: Tue Feb 21 14:53:07 2012 +1100
net: add diagnostic to try to catch selfConnect bug earlier
TBR=dsymonds
R=golang-dev
CC=golang-dev
https://golang.org/cl/5683057
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/2155a0408eb50ce8ae47d5b3b53c3363498cd716
元コミット内容
net: add diagnostic to try to catch selfConnect bug earlier
TBR=dsymonds
R=golang-dev
CC=golang-dev
https://golang.org/cl/5683057
変更の背景
このコミットの主な背景は、Go言語の net
パッケージにおける selfConnect
と呼ばれる特定のバグの存在です。selfConnect
は、TCP接続を確立する際に、クライアントが自分自身に接続しようとしてしまう、非常に稀な競合状態によって発生する問題です。これは、特に同時接続(simultaneous connection)のメカニズムが関与する場合に顕在化することがありました。
Goの net
パッケージは、内部的に syscall
パッケージを使用してOSのソケットAPIを呼び出しています。DialTCP
関数は、指定されたリモートアドレス(raddr
)への接続を試みますが、何らかの理由で fd.raddr
(ファイルディスクリプタに関連付けられたリモートアドレス) が nil
になるという異常な状態が発生することがありました。この nil
の raddr
は、後続の処理でパニックを引き起こす可能性があり、デバッグが困難でした。
このコミットは、この selfConnect
バグが実際に発生する前に、fd.raddr
が nil
であるという異常な状態を早期に検出し、パニックを発生させることで、問題の根本原因を特定しやすくするための診断メカニズムを追加しています。これにより、開発者はより迅速に問題を特定し、修正に取り組むことができるようになります。
前提知識の解説
TCP/IPとソケットプログラミング
TCP/IPはインターネットの基盤となる通信プロトコル群です。TCP(Transmission Control Protocol)は、信頼性の高いコネクション指向の通信を提供し、データの順序保証や再送制御を行います。ソケットは、ネットワーク通信のエンドポイントを表す抽象化された概念で、アプリケーションがネットワーク経由でデータを送受信するためのインターフェースを提供します。
net
パッケージ (Go言語)
Go言語の net
パッケージは、ネットワークI/Oのためのポータブルなインターフェースを提供します。TCP/IP、UDP、Unixドメインソケットなど、様々なネットワークプロトコルをサポートしています。DialTCP
関数は、TCPネットワーク上でリモートアドレスへの接続を確立するために使用されます。
DialTCP
関数
DialTCP
は net
パッケージの関数で、以下のようなシグネチャを持ちます。
func DialTCP(net string, laddr, raddr *TCPAddr) (*TCPConn, error)
net
: "tcp", "tcp4", "tcp6" などのネットワークタイプを指定します。laddr
: ローカルアドレス(オプション)。指定しない場合、OSが適切なローカルアドレスを選択します。raddr
: リモートアドレス。接続先のアドレスを指定します。- 戻り値: 成功した場合は
*TCPConn
(TCP接続を表す構造体)とnil
エラー、失敗した場合はnil
とエラーを返します。
TCPAddr
構造体
TCPAddr
は、TCPネットワークアドレスを表す構造体です。IPアドレスとポート番号を含みます。
internetSocket
関数
internetSocket
は net
パッケージ内部で使用される関数で、指定されたネットワークタイプ、ローカルアドレス、リモートアドレス、ソケットタイプ(例: syscall.SOCK_STREAM
)、プロトコルなどに基づいてソケットを作成し、接続を試みます。この関数は、OSのシステムコールをラップしています。
fd.raddr
fd
はファイルディスクリプタ(file descriptor)を表す内部的な構造体で、ネットワーク接続に関する情報(ローカルアドレス、リモートアドレスなど)を保持しています。fd.raddr
は、このファイルディスクリプタに関連付けられたリモートアドレスを指します。正常なTCP接続では、この raddr
は接続先のリモートアドレスを保持している必要があります。
selfConnect
バグ
selfConnect
は、TCPの同時接続(simultaneous connection)メカニズムに関連する稀なケースで発生する可能性のあるバグです。通常、TCP接続はクライアントがサーバーに接続要求を送信し、サーバーがそれを受け入れるという非対称なプロセスで行われます。しかし、TCPプロトコルには、両方のエンドポイントが同時に connect
(または Dial
) を呼び出し、互いに接続しようとする「同時接続」というメカニズムが存在します。このメカニズムは非常に稀にしか使用されませんが、特定の条件下で DialTCP
が自分自身に接続してしまうような論理的な問題を引き起こすことがありました。このバグが発生すると、fd.raddr
が適切に設定されず nil
になることがあり、後続の処理で問題を引き起こす可能性がありました。
panic
Go言語における panic
は、プログラムの実行を停止させる回復不可能なエラーを示します。通常、予期せぬプログラミングエラーや、プログラムが続行できないような致命的な状態に陥った場合に発生させます。このコミットでは、nil raddr
という異常な状態を早期に panic
させることで、開発者がデバッグしやすいようにしています。
技術的詳細
このコミットは、src/pkg/net/tcpsock_posix.go
ファイルの DialTCP
関数に診断ロジックを追加しています。
DialTCP
関数は、まず internetSocket
を呼び出してソケットを作成し、接続を試みます。この internetSocket
の呼び出し後、fd
(ファイルディスクリプタ) が返されます。この fd
には、接続が成功した場合、リモートアドレス情報が fd.raddr
として設定されているはずです。
追加された診断コードは、以下の checkRaddr
という匿名関数です。
checkRaddr := func(s string) {
if err == nil && fd.raddr == nil {
panic("nil raddr in DialTCP: " + s)
}
}
この関数は、以下の条件をチェックします。
err == nil
:internetSocket
の呼び出しでエラーが発生していないこと。つまり、ソケットの作成と初期接続は成功していると見なされる状態。fd.raddr == nil
: にもかかわらず、fd
のリモートアドレス (raddr
) がnil
であること。
この両方の条件が真である場合、それは異常な状態であり、"nil raddr in DialTCP: " + s
というメッセージと共に panic
を発生させます。s
は、checkRaddr
が呼び出された場所を示す文字列("early" または "after close")です。
この checkRaddr
関数は、DialTCP
関数内の2つの重要なポイントで呼び出されます。
-
internetSocket
呼び出し直後 (checkRaddr("early")
): 最初のinternetSocket
呼び出しが成功した直後に、fd.raddr
がnil
でないことを確認します。これにより、初期接続フェーズでのnil raddr
の問題を早期に捕捉します。 -
selfConnect
リトライループ内 (checkRaddr("after close")
):DialTCP
関数には、selfConnect
バグを検出して再試行するためのループが存在します。このループは、selfConnect(fd)
が真(つまり、自分自身に接続してしまった)であり、かつladdr
がnil
(ローカルアドレスが指定されていない)の場合に、既存のソケットを閉じ、再度internetSocket
を呼び出して接続を試みます。この再試行の後にも、fd.raddr
がnil
になっていないかをcheckRaddr("after close")
で確認します。これにより、再試行プロセス中に発生する可能性のあるnil raddr
の問題も捕捉します。
この診断コードの追加により、selfConnect
バグやその他の関連する競合状態によって fd.raddr
が nil
になるという、通常ではありえない状態が発生した場合に、プログラムが静かに続行して後でより理解しにくいエラーを引き起こすのではなく、即座に panic
することで、問題の根本原因を特定しやすくなります。これは、開発者がデバッグを行う上で非常に有用な情報を提供します。
コアとなるコードの変更箇所
src/pkg/net/tcpsock_posix.go
ファイルの DialTCP
関数に以下のコードが追加されました。
--- a/src/pkg/net/tcpsock_posix.go
+++ b/src/pkg/net/tcpsock_posix.go
@@ -230,6 +230,13 @@ func DialTCP(net string, laddr, raddr *TCPAddr) (*TCPConn, error) {
fd, err := internetSocket(net, laddr.toAddr(), raddr.toAddr(), syscall.SOCK_STREAM, 0, "dial", sockaddrToTCP)
+ checkRaddr := func(s string) {
+ if err == nil && fd.raddr == nil {
+ panic("nil raddr in DialTCP: " + s)
+ }
+ }
+ checkRaddr("early")
+
// TCP has a rarely used mechanism called a 'simultaneous connection' in
// which Dial("tcp", addr1, addr2) run on the machine at addr1 can
// connect to a simultaneous Dial("tcp", addr2, addr1) run on the machine
@@ -250,6 +257,7 @@ func DialTCP(net string, laddr, raddr *TCPAddr) (*TCPConn, error) {
for i := 0; i < 2 && err == nil && laddr == nil && selfConnect(fd); i++ {
fd.Close()
fd, err = internetSocket(net, laddr.toAddr(), raddr.toAddr(), syscall.SOCK_STREAM, 0, "dial", sockaddrToTCP)
+ checkRaddr("after close")
}
if err != nil {
コアとなるコードの解説
追加されたコードは、DialTCP
関数内で fd
(ファイルディスクリプタ) の raddr
(リモートアドレス) が nil
になっていないかをチェックする診断ロジックです。
-
checkRaddr
匿名関数の定義:checkRaddr
という名前の匿名関数が定義されています。この関数は文字列s
を引数に取り、診断メッセージの一部として使用します。 この関数は、internetSocket
の呼び出しでエラーが発生しておらず (err == nil
)、かつfd.raddr
がnil
である場合にpanic
を発生させます。これは、接続が成功したと見なされるにもかかわらず、リモートアドレス情報が欠落しているという矛盾した状態を検出するためのものです。 -
checkRaddr("early")
: 最初のinternetSocket
呼び出しの直後にcheckRaddr("early")
が呼び出されます。これは、接続確立の初期段階でfd.raddr
が正しく設定されていることを確認するためのものです。もしここでnil raddr
が検出されれば、初期接続プロセスに問題があることを示します。 -
checkRaddr("after close")
:DialTCP
関数には、selfConnect
バグを処理するための再試行ループがあります。このループは、selfConnect(fd)
が真(自分自身に接続してしまった)の場合に、既存のソケットを閉じ (fd.Close()
)、再度internetSocket
を呼び出して接続を試みます。この再試行の直後にcheckRaddr("after close")
が呼び出されます。これは、再試行プロセスがnil raddr
の状態を引き起こしていないことを確認するためのものです。
この診断コードは、本番環境で通常発生しないような、非常に稀な競合状態やバグによって fd.raddr
が nil
になるケースを早期に特定し、デバッグを容易にすることを目的としています。panic
を発生させることで、問題の発生箇所と状況を明確にし、開発者が根本原因を追跡できるようにします。
関連リンク
- Go言語
net
パッケージのドキュメント: https://pkg.go.dev/net - Go言語の
syscall
パッケージのドキュメント: https://pkg.go.dev/syscall - TCP Simultaneous Open (同時接続) について: https://www.rfc-editor.org/rfc/rfc793 (RFC 793 - Transmission Control Protocol)
参考にした情報源リンク
- Go言語の公式リポジトリ: https://github.com/golang/go
- Gerrit Change-ID 5683057: https://golang.org/cl/5683057 (このコミットに対応するGoのコードレビューシステムのエントリ)
- Go言語の
net
パッケージのソースコード (特にtcpsock_posix.go
): https://github.com/golang/go/blob/master/src/net/tcpsock_posix.go - Go言語の
net
パッケージにおけるselfConnect
バグに関する議論や関連するIssue (当時の情報源を特定するのは困難ですが、GoのIssueトラッカーやメーリングリストで関連する議論が見つかる可能性があります)
[インデックス 12097] ファイルの概要
このコミットは、Go言語の標準ライブラリである net
パッケージ内の tcpsock_posix.go
ファイルに対する変更です。具体的には、TCP接続の確立処理において、selfConnect
と呼ばれる稀なバグを早期に検出するための診断コードが追加されています。この変更は、Goのネットワークスタックの堅牢性を向上させることを目的としています。
コミット
commit 2155a0408eb50ce8ae47d5b3b53c3363498cd716
Author: Rob Pike <r@golang.org>
Date: Tue Feb 21 14:53:07 2012 +1100
net: add diagnostic to try to catch selfConnect bug earlier
TBR=dsymonds
R=golang-dev
CC=golang-dev
https://golang.org/cl/5683057
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/2155a0408eb50ce8ae47d5b3b53c3363498cd716
元コミット内容
net: add diagnostic to try to catch selfConnect bug earlier
TBR=dsymonds
R=golang-dev
CC=golang-dev
https://golang.org/cl/5683057
変更の背景
このコミットの主な背景は、Go言語の net
パッケージにおける selfConnect
と呼ばれる特定のバグの存在です。selfConnect
は、TCP接続を確立する際に、クライアントが自分自身に接続しようとしてしまう、非常に稀な競合状態によって発生する問題です。これは、特に同時接続(simultaneous connection)のメカニズムが関与する場合に顕在化することがありました。
Goの net
パッケージは、内部的に syscall
パッケージを使用してOSのソケットAPIを呼び出しています。DialTCP
関数は、指定されたリモートアドレス(raddr
)への接続を試みますが、何らかの理由で fd.raddr
(ファイルディスクリプタに関連付けられたリモートアドレス) が nil
になるという異常な状態が発生することがありました。この nil
の raddr
は、後続の処理でパニックを引き起こす可能性があり、デバッグが困難でした。
このコミットは、この selfConnect
バグが実際に発生する前に、fd.raddr
が nil
であるという異常な状態を早期に検出し、パニックを発生させることで、問題の根本原因を特定しやすくするための診断メカニズムを追加しています。これにより、開発者はより迅速に問題を特定し、修正に取り組むことができるようになります。
前提知識の解説
TCP/IPとソケットプログラミング
TCP/IPはインターネットの基盤となる通信プロトコル群です。TCP(Transmission Control Protocol)は、信頼性の高いコネクション指向の通信を提供し、データの順序保証や再送制御を行います。ソケットは、ネットワーク通信のエンドポイントを表す抽象化された概念で、アプリケーションがネットワーク経由でデータを送受信するためのインターフェースを提供します。
net
パッケージ (Go言語)
Go言語の net
パッケージは、ネットワークI/Oのためのポータブルなインターフェースを提供します。TCP/IP、UDP、Unixドメインソケットなど、様々なネットワークプロトコルをサポートしています。DialTCP
関数は、TCPネットワーク上でリモートアドレスへの接続を確立するために使用されます。
DialTCP
関数
DialTCP
は net
パッケージの関数で、以下のようなシグネチャを持ちます。
func DialTCP(net string, laddr, raddr *TCPAddr) (*TCPConn, error)
net
: "tcp", "tcp4", "tcp6" などのネットワークタイプを指定します。laddr
: ローカルアドレス(オプション)。指定しない場合、OSが適切なローカルアドレスを選択します。raddr
: リモートアドレス。接続先のアドレスを指定します。- 戻り値: 成功した場合は
*TCPConn
(TCP接続を表す構造体)とnil
エラー、失敗した場合はnil
とエラーを返します。
TCPAddr
構造体
TCPAddr
は、TCPネットワークアドレスを表す構造体です。IPアドレスとポート番号を含みます。
internetSocket
関数
internetSocket
は net
パッケージ内部で使用される関数で、指定されたネットワークタイプ、ローカルアドレス、リモートアドレス、ソケットタイプ(例: syscall.SOCK_STREAM
)、プロトコルなどに基づいてソケットを作成し、接続を試みます。この関数は、OSのシステムコールをラップしています。
fd.raddr
fd
はファイルディスクリプタ(file descriptor)を表す内部的な構造体で、ネットワーク接続に関する情報(ローカルアドレス、リモートアドレスなど)を保持しています。fd.raddr
は、このファイルディスクリプタに関連付けられたリモートアドレスを指します。正常なTCP接続では、この raddr
は接続先のリモートアドレスを保持している必要があります。
selfConnect
バグ
selfConnect
は、TCPの同時接続(simultaneous connection)メカニズムに関連する稀なケースで発生する可能性のあるバグです。通常、TCP接続はクライアントがサーバーに接続要求を送信し、サーバーがそれを受け入れるという非対称なプロセスで行われます。しかし、TCPプロトコルには、両方のエンドポイントが同時に connect
(または Dial
) を呼び出し、互いに接続しようとする「同時接続」というメカニズムが存在します。このメカニズムは非常に稀にしか使用されませんが、特定の条件下で DialTCP
が自分自身に接続してしまうような論理的な問題を引き起こすことがありました。このバグが発生すると、fd.raddr
が適切に設定されず nil
になることがあり、後続の処理で問題を引き起こす可能性がありました。
panic
Go言語における panic
は、プログラムの実行を停止させる回復不可能なエラーを示します。通常、予期せぬプログラミングエラーや、プログラムが続行できないような致命的な状態に陥った場合に発生させます。このコミットでは、nil raddr
という異常な状態を早期に panic
させることで、開発者がデバッグしやすいようにしています。
技術的詳細
このコミットは、src/pkg/net/tcpsock_posix.go
ファイルの DialTCP
関数に診断ロジックを追加しています。
DialTCP
関数は、まず internetSocket
を呼び出してソケットを作成し、接続を試みます。この internetSocket
の呼び出し後、fd
(ファイルディスクリプタ) が返されます。この fd
には、接続が成功した場合、リモートアドレス情報が fd.raddr
として設定されているはずです。
追加された診断コードは、以下の checkRaddr
という匿名関数です。
checkRaddr := func(s string) {
if err == nil && fd.raddr == nil {
panic("nil raddr in DialTCP: " + s)
}
}
この関数は、以下の条件をチェックします。
err == nil
:internetSocket
の呼び出しでエラーが発生していないこと。つまり、ソケットの作成と初期接続は成功していると見なされる状態。fd.raddr == nil
: にもかかわらず、fd
のリモートアドレス (raddr
) がnil
であること。
この両方の条件が真である場合、それは異常な状態であり、"nil raddr in DialTCP: " + s
というメッセージと共に panic
を発生させます。s
は、checkRaddr
が呼び出された場所を示す文字列("early" または "after close")です。
この checkRaddr
関数は、DialTCP
関数内の2つの重要なポイントで呼び出されます。
-
internetSocket
呼び出し直後 (checkRaddr("early")
): 最初のinternetSocket
呼び出しが成功した直後に、fd.raddr
がnil
でないことを確認します。これにより、初期接続フェーズでのnil raddr
の問題を早期に捕捉します。 -
selfConnect
リトライループ内 (checkRaddr("after close")
):DialTCP
関数には、selfConnect
バグを検出して再試行するためのループが存在します。このループは、selfConnect(fd)
が真(つまり、自分自身に接続してしまった)であり、かつladdr
がnil
(ローカルアドレスが指定されていない)の場合に、既存のソケットを閉じ、再度internetSocket
を呼び出して接続を試みます。この再試行の後にも、fd.raddr
がnil
になっていないかをcheckRaddr("after close")
で確認します。これにより、再試行プロセス中に発生する可能性のあるnil raddr
の問題も捕捉します。
この診断コードの追加により、selfConnect
バグやその他の関連する競合状態によって fd.raddr
が nil
になるという、通常ではありえない状態が発生した場合に、プログラムが静かに続行して後でより理解しにくいエラーを引き起こすのではなく、即座に panic
することで、問題の根本原因を特定しやすくなります。これは、開発者がデバッグを行う上で非常に有用な情報を提供します。
コアとなるコードの変更箇所
src/pkg/net/tcpsock_posix.go
ファイルの DialTCP
関数に以下のコードが追加されました。
--- a/src/pkg/net/tcpsock_posix.go
+++ b/src/pkg/net/tcpsock_posix.go
@@ -230,6 +230,13 @@ func DialTCP(net string, laddr, raddr *TCPAddr) (*TCPConn, error) {
fd, err := internetSocket(net, laddr.toAddr(), raddr.toAddr(), syscall.SOCK_STREAM, 0, "dial", sockaddrToTCP)
+ checkRaddr := func(s string) {
+ if err == nil && fd.raddr == nil {
+ panic("nil raddr in DialTCP: " + s)
+ }
+ }
+ checkRaddr("early")
+
// TCP has a rarely used mechanism called a 'simultaneous connection' in
// which Dial("tcp", addr1, addr2) run on the machine at addr1 can
// connect to a simultaneous Dial("tcp", addr2, addr1) run on the machine
@@ -250,6 +257,7 @@ func DialTCP(net string, laddr, raddr *TCPAddr) (*TCPConn, error) {
for i := 0; i < 2 && err == nil && laddr == nil && selfConnect(fd); i++ {
fd.Close()
fd, err = internetSocket(net, laddr.toAddr(), raddr.toAddr(), syscall.SOCK_STREAM, 0, "dial", sockaddrToTCP)
+ checkRaddr("after close")
}
if err != nil {
コアとなるコードの解説
追加されたコードは、DialTCP
関数内で fd
(ファイルディスクリプタ) の raddr
(リモートアドレス) が nil
になっていないかをチェックする診断ロジックです。
-
checkRaddr
匿名関数の定義:checkRaddr
という名前の匿名関数が定義されています。この関数は文字列s
を引数に取り、診断メッセージの一部として使用します。 この関数は、internetSocket
の呼び出しでエラーが発生しておらず (err == nil
)、かつfd.raddr
がnil
である場合にpanic
を発生させます。これは、接続が成功したと見なされるにもかかわらず、リモートアドレス情報が欠落しているという矛盾した状態を検出するためのものです。 -
checkRaddr("early")
: 最初のinternetSocket
呼び出しの直後にcheckRaddr("early")
が呼び出されます。これは、接続確立の初期段階でfd.raddr
が正しく設定されていることを確認するためのものです。もしここでnil raddr
が検出されれば、初期接続プロセスに問題があることを示します。 -
checkRaddr("after close")
:DialTCP
関数には、selfConnect
バグを処理するための再試行ループがあります。このループは、selfConnect(fd)
が真(自分自身に接続してしまった)の場合に、既存のソケットを閉じ (fd.Close()
)、再度internetSocket
を呼び出して接続を試みます。この再試行の直後にcheckRaddr("after close")
が呼び出されます。これは、再試行プロセスがnil raddr
の状態を引き起こしていないことを確認するためのものです。
この診断コードは、本番環境で通常発生しないような、非常に稀な競合状態やバグによって fd.raddr
が nil
になるケースを早期に特定し、デバッグを容易にすることを目的としています。panic
を発生させることで、問題の発生箇所と状況を明確にし、開発者が根本原因を追跡できるようにします。
関連リンク
- Go言語
net
パッケージのドキュメント: https://pkg.go.dev/net - Go言語の
syscall
パッケージのドキュメント: https://pkg.go.dev/syscall - TCP Simultaneous Open (同時接続) について: https://www.rfc-editor.org/rfc/rfc793 (RFC 793 - Transmission Control Protocol)
参考にした情報源リンク
- Go言語の公式リポジトリ: https://github.com/golang/go
- Gerrit Change-ID 5683057: https://golang.org/cl/5683057 (このコミットに対応するGoのコードレビューシステムのエントリ)
- Go言語の
net
パッケージのソースコード (特にtcpsock_posix.go
): https://github.com/golang/go/blob/master/src/net/tcpsock_posix.go - Go net selfConnect bugに関するWeb検索結果:
- https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQFG09TUnJyql_X4oWaqAnin2n02VX4Ke1XCLAkmlvhXFDBSQjXnubOXi9SiDS7N_Lwkywnl9qIv_yd_fWVFTiVTg519MZUyPyO6zToJiLmuwcn8j0qcsMK4tiCJBYEE0yFfksMQOHk772fTnfQS0X5wbi42U9CeVN0=
- https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQGwXWciWdw_Jdi2d-XMMRoarJ5B_8ruk6xu9YBo3U0RRW1IBOH2EgbJn0PFprzpDPkKIwTm79S2TKhHjKI9jn3P0i3ZMzvD2f-xGd9wlWq9c7wfcUvTw98Yahwx1C757pWSqe_G
- https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQG-tEADLRZMx18NwnQ01vCIK8kcTXQv6mMbEScoZH1LtZGAGHBsv_LHfHyN8UScpE7N0-M1NCVNDKcuttk5GJ9SvRj_l-NIi7oBrfubjl8SiahKkzzRsjft_oAnvfGmlQKr