Rcloneを便利に使う(stable diffusionの画像出力先変更)

7月 1, 2024

Rcloneは、クラウドストレージサービス間でデータを効率的に同期、バックアップ、マウントできるコマンドラインツールです。

主な機能

  1. 多くのクラウドストレージサービスをサポート:
    • Google Drive、Dropbox、Amazon S3、OneDriveなど、多数のクラウドストレージサービスに対応しています。実際に確認したら80以上のサービスに対応していました。
  2. データの同期とバックアップ:
    • ローカルストレージとクラウドストレージ間、あるいはクラウドストレージ間でのデータ同期やバックアップが簡単に行えます。
  3. マウント機能:
    • クラウドストレージをローカルディスクのようにマウントし、ファイルエクスプローラーから直接アクセスできます。
  4. 高いパフォーマンス:
    • 大容量ファイルの転送や多くのファイルの操作に対して高いパフォーマンスを発揮します。

メリット

  • オープンソース: 無料で利用可能。
  • 多機能: 豊富なオプションとカスタマイズが可能。
  • クロスプラットフォーム: Windows、Mac、Linuxで利用可能。

以前導入方法を紹介しました。WindowsとLinux版をインストールしているとして応用例を説明したいと思います。すでに活用しているものとしてWordpressのバックアップとして利用しています。

https://minokamo.tokyo/2024/02/18/6935

今回は、Windows版とLinux版のRcloneでStable Diffusionの画像出力先をオンラインストレージにする例を紹介します。WindowsではPythonの仮想環境を使用してStable Diffusion Web Uiをインストールすると次のような場所に画像が出力されます。

C:youtubestable-diffusion-webuioutputs

以前はシンボリックリンクでこれを実現していたのですが、Rcloneで試したら思った以上に便利でした。というのもsftpなどにも対応しているので、例えばロリポップの余ったストレージに保存して有効活用することもできるからです。それでは実際に作業をしていきましょう。

既にRcloneがインストールされており、リモート設定が完了していることを前提とします。rclone configコマンドでリモートストレージ(例:Dropbox、Google Driveなど)を設定をしておきます。リモート設定をしたのは日本のレンタルサーバー(ロリポップのアカウントで設定しました)でよく見かけるSFTPです。まずはリモートストレージを画像出力先のフォルダにマウントします。

rclone mount losftp:web/stable C:\youtube\stable-diffusion-webui\outputs

outputs配下のファイルやフォルダは削除しておいた方が無難です。つまりoutputsの中身が空の状態にしておきます。必要に応じてバックアップしてから削除しておきます。しかしエラーになりました。

Fatal error: failed to mount FUSE fs: mountpoint path already exists: C:\youtube\stable-diffusion-webui\outputs

WindowsでRcloneのmount機能を使用するためには、WinFsp(Windows File System Proxy)が必要かもしれません。というわけで公式からダウンロードしてインストールします。

https://winfsp.dev

WinFsp(Windows File System Proxy)は、Windows環境でユーザー空間のファイルシステムを実装するためのツールキットです。このツールを使えば、開発者はカスタムファイルシステムをユーザー空間で実装し、標準のWindowsファイルシステムインターフェイスを通じてアクセスできるようにすることができます。

WinFspの役割と機能

  1. ユーザー空間ファイルシステムの実装:
    • 通常、ファイルシステムはカーネルモードで実装されますが、WinFspを使用すると、ユーザー空間でファイルシステムを実装できます。これにより、開発が容易になり、デバッグも簡単になります。
  2. カスタムファイルシステムのサポート:
    • 開発者は、特定のニーズに合わせたカスタムファイルシステムを作成できます。たとえば、クラウドストレージやリモートファイルシステムをローカルファイルシステムとして扱うことができます。
  3. FUSE互換性:
    • WinFspは、LinuxのFUSE(Filesystem in Userspace)と互換性があるため、FUSEベースのファイルシステムをWindowsに移植する際に便利です。

WinFspとLinuxのファイルシステムの問題解決

WinFsp自体は、WindowsとLinuxのファイルシステム間の互換性問題を直接解決するツールではありませんが、以下の方法で役立つことがあります。

  1. FUSEファイルシステムの移植:
    • WinFspを使用することで、LinuxのFUSEベースのファイルシステムをWindowsに移植し、Windowsアプリケーションからアクセスできるようにすることができます。これにより、クロスプラットフォームのファイルシステムアクセスが可能になります。
  2. カスタムファイルシステムの作成:
    • 開発者は、WinFspを使用して、特定のLinuxファイルシステム(例:ext4、XFS)と互換性のあるカスタムファイルシステムを作成し、Windowsからアクセスできるようにすることができます。
  3. クラウドストレージやリモートストレージの統合:
    • Rcloneのようなツールと組み合わせることで、クラウドストレージやリモートストレージをWindowsファイルシステムとしてマウントし、シームレスにアクセスできるようになります。

ダウンロードしたインストーラを実行し、画面の指示に従ってインストールします。インストール後にサービスとして実行されていることを確認します。サービスマネージャ(services.msc)を開き、「WinFsp.Launcher」が「実行中」になっていることを確認します。もしくは次の方法もあります。通常、WinFspはC:\Program Files (x86)\WinFspにインストールされます。ここにあるfsptool-x64.exeを実行して、WinFspが正しく動作していることを確認します。

再度マウントするコマンドを入力すると今度はうまくいきました。またoutputs自体も削除しておく必要があることに後で気が付きました。WinFspをインストールしていないと、outputsフォルダが無くてもエラーになります。

Rcloneでリモートストレージをマウントすると、マウントされたフォルダのアイコンが通常のフォルダアイコンとは異なる場合があります。これは、マウントされたリモートストレージが特定のファイルシステムやプロトコルを使用していることを示しています。

なぜアイコンが異なるのか

  1. ファイルシステムの違い:
    • マウントされたリモートストレージは、ローカルのファイルシステムとは異なるファイルシステムを使用しているため、異なるアイコンが表示されることがあります。
  2. マウントポイントの識別:
    • オペレーティングシステムがマウントポイントを通常のフォルダと区別するために、異なるアイコンを使用することがあります。これにより、ユーザーはそのフォルダがリモートストレージであることを一目で認識できます。

  • Windowsの場合:
    • マウントされたリモートストレージのフォルダは、ネットワークドライブのようなアイコンになることがあります。
  • Linuxの場合:
    • マウントポイントのフォルダは、通常のフォルダアイコンとは異なるマークが付くことがあります。

今度は、再起動後にマウント設定を自動的に行うことができます。これを実現するために、最初はバッチファイルを作成してWindowsのタスクスケジューラでシステム起動時に実行していましたがコマンドプロンプトが出っぱなしで違和感がありました。そこでNSSMを使用してRcloneをWindowsサービスとして実行することにしました。

https://nssm.cc

NSSM(Non-Sucking Service Manager)を使用する方法

NSSMを使用してRcloneをWindowsサービスとして実行すると、コマンドプロンプトのウィンドウが表示されず、サービスとしてバックグラウンドで実行されるため、ウィンドウを閉じてもマウントが解除されません。

  1. NSSMのダウンロードとインストール
    • NSSMの公式サイトからNSSMをダウンロードします。
    • ダウンロードしたZIPファイルを解凍し、nssm.exeを適当な場所に配置します(例:C:\nssm\nssm.exe)。
  2. NSSMを使用してRcloneをサービスとしてインストール
    • コマンドプロンプトを管理者として開き、以下のコマンドを実行します。
    C:\nssm\nssm.exe install rclone_mount
  3. サービスの設定
    • NSSMのインターフェースが開くので、以下の設定を行います。
    Application タブ:
    • Pathrclone.exe のフルパスを指定します(例:C:\Program Files\rclone\rclone.exe)。Startup directory に Rclone のディレクトリパスを指定します。Arguments に次を入力します。mount losftp:web/stable C:\youtube\stable-diffusion-webui\outputs --vfs-cache-mode writes --config "C:Users\yourusername.config\rclone\rclone.conf"
    Details タブ:
    • Display name にわかりやすいサービス名を入力します(例:Rclone Mount)。
  4. サービスの起動
    • NSSMの設定を保存し、以下のコマンドでサービスを起動します。
    net start rclone_mount
    またはWindowsのサービスマネージャで開始します。少しでも間違っているとエラーになります。

–config “C:\Users\yourusername\.config\rclone\rclone.conf"について
rclone.confをメモ帳で見ると認証情報が記述されていました。rclone.confの場所は以下のコマンドで確認できます。

rclone config file

–vfs-cache-mode writesについて
Rcloneでマウントされたオンラインストレージのファイルがどのように扱われるかは、使用するVFSキャッシュモードに依存します。RcloneにはいくつかのVFSキャッシュモードがあり、それぞれが異なる方法でファイルを処理します。以下は主なモードの概要です。

  1. オフ (off):
    • デフォルトのモードです。
    • ファイルは直接リモートストレージから読み書きされます。
    • オンラインファイルとして扱われ、オンデマンドでダウンロードされます。
    • 一時的なキャッシュが使われることはありません。
  2. 読み込みキャッシュ (minimal):
    • ファイルの読み取り中に、データが一時的にキャッシュされます。
    • オンラインファイルとして扱われ、必要に応じてダウンロードされます。
    • ファイルの読み取りが完了するとキャッシュがクリアされます。
  3. 書き込みキャッシュ (writes):
    • ファイルがローカルにキャッシュされ、書き込み操作が完了した後にリモートにアップロードされます。
    • 読み取り時には直接リモートからデータが取得されます。
    • 主に書き込みパフォーマンスを向上させるために使用されます。
  4. フルキャッシュ (full):
    • 読み取りも書き込みもローカルにキャッシュされます。
    • 初回アクセス時にファイルがダウンロードされ、その後ローカルキャッシュからアクセスされます。
    • オフラインファイルのように扱われ、キャッシュが削除されるまでローカルで保持されます。

結局のところ、モードにかかわらず、最終的にはファイルはオンラインストレージに保存されます。これで、RcloneがWindowsサービスとしてバックグラウンドで実行されるようになります。サービスを削除するときは以下のコマンドを使用します。

nssm remove サービス名

ほかに考えられる方法として、Rclone以外にも、ファイルがローカルに保存されたら、それを移動するスクリプトを使用することもできます。例えば、バッチファイルやシェルスクリプトを使って、ローカルディレクトリに保存されたファイルを定期的にチェックし、リモートストレージに移動するように設定できます。これにより、特定のクラウドストレージサービスへの対応が簡単になります。

スクリプトの例

Windowsのバッチファイル

@echo off
setlocal

REM ローカルディレクトリ
set LOCAL_DIR=C:\path\to\local\directory

REM リモートディレクトリ
set REMOTE_DIR=\\path\to\remote\directory

REM ローカルディレクトリのファイルをリモートディレクトリに移動
move "%LOCAL_DIR%\*" "%REMOTE_DIR%"

endlocal

Linuxのシェルスクリプト

#!/bin/bash

# ローカルディレクトリ
LOCAL_DIR="/path/to/local/directory"

# リモートディレクトリ
REMOTE_DIR="/path/to/remote/directory"

# ローカルディレクトリのファイルをリモートディレクトリに移動
mv "$LOCAL_DIR"/* "$REMOTE_DIR"

これらのスクリプトを使用すると、ローカルディレクトリに保存されたファイルを定期的にリモートディレクトリに移動することができます。この方法は、特定のクラウドストレージサービスやリモートサーバーに対しても応用できます。

リアルタイム性を求める場合、ファイルシステムイベントを監視してファイルが作成された瞬間に移動する方法が効果的です。以下に、リアルタイムでファイルを移動する方法を説明します。

Windows環境

Windowsでは、PowerShellを使用してファイルシステムイベントを監視し、ファイルが作成されたときにリアルタイムで移動するスクリプトを作成できます。

PowerShellスクリプトの例

$watcher = New-Object System.IO.FileSystemWatcher
$watcher.Path = "C:\path\to\local\directory"
$watcher.Filter = "*.*"
$watcher.IncludeSubdirectories = $false
$watcher.EnableRaisingEvents = $true

$action = {
$sourcePath = $Event.SourceEventArgs.FullPath
$destinationPath = "C:\path\to\remote\directory\" + $Event.SourceEventArgs.Name
Move-Item -Path $sourcePath -Destination $destinationPath
}

Register-ObjectEvent $watcher "Created" -Action $action

# スクリプトを終了せずに待機
while ($true) { Start-Sleep 1 }

Linux環境

Linuxでは、inotifyツールを使用してファイルシステムイベントを監視し、ファイルが作成されたときにリアルタイムで移動するスクリプトを作成できます。

シェルスクリプトの例

#!/bin/bash

LOCAL_DIR="/path/to/local/directory"
REMOTE_DIR="/path/to/remote/directory"

inotifywait -m -e create "$LOCAL_DIR" |
while read path action file; do
mv "$LOCAL_DIR/$file" "$REMOTE_DIR"
done

macOS環境

macOSでは、fswatchツールを使用してファイルシステムイベントを監視し、ファイルが作成されたときにリアルタイムで移動するスクリプトを作成できます。

シェルスクリプトの例

#!/bin/bash

LOCAL_DIR="/path/to/local/directory"
REMOTE_DIR="/path/to/remote/directory"

fswatch -0 "$LOCAL_DIR" | while read -d "" event; do
mv "$event" "$REMOTE_DIR"
done

次はubuntuでも同様なことができる設定をします。Windowsでは既存のフォルダに対してマウントしようとするとエラーが発生しましたが、Ubuntuでは既存のディレクトリに対してRcloneのマウントが問題なく行えました。以下のコマンドは手動でマウントします。

rclone mount dropb:stableout /home/mamu/stable-diffusion-webui/outputs

手動で成功したので、systemdサービスとして実行する方法が公式ページにあります。これを参考に設定します。

https://rclone.org/commands/rclone_mount

次のことを行います。

Rcloneのサービス化は、システムの再起動後でも自動的にリモートストレージをマウントするために必要です。これを達成するためには、シンボリックリンクとユニットファイルの設定が重要な役割を果たします。以下に、それぞれの要素がなぜ必要なのかを説明します。

1. シンボリックリンク

シンボリックリンクとは?

シンボリックリンクは、あるファイルやディレクトリへの参照を指し示す特別なファイルです。ショートカットのようなものと考えてください。

なぜシンボリックリンクが必要か?

Rcloneを使ってファイルシステムとしてリモートストレージをマウントする際、システムの一部のツールがRcloneを認識するために特別なファイルパスが必要です。シンボリックリンクを作成することで、Rcloneがその特別なファイルパスとして認識され、スムーズに動作します。具体的には、システムはRcloneを「マウントツール」として認識し、適切に処理することができます。

2. ユニットファイル

ユニットファイルとは?

ユニットファイルは、システムが特定のサービスやタスクを管理するための設定ファイルです。これを作成するとシステムはどのように、いつ特定のサービスを開始するかを知ります。

なぜユニットファイルが必要か?

ユニットファイルは、リモートストレージのマウントを自動化するための指示書のようなものです。2つのユニットファイルが必要です。

  1. マウントユニットファイル
    • これは、リモートストレージをどのようにマウントするかを定義します。リモートストレージの場所(例えばDropboxの特定フォルダ)と、マウントポイント(どこにマウントするか)を指定します。
  2. オートマウントユニットファイル
    • これは、システムが必要になったときに自動的にマウントを開始するように指示します。例えば、システムが再起動したときや、特定のディレクトリにアクセスしたときに自動的にマウントを開始します。

まとめ

  • シンボリックリンクは、Rcloneをシステムの一部のツールが認識できるようにするための「ショートカット」です。
  • ユニットファイルは、システムにリモートストレージを自動的にマウントする方法とタイミングを指示する「設定ファイル」です。

このように設定することで、システムは再起動後でもリモートストレージを自動的にマウントし、ユーザーは手動でマウント作業を行う必要がなくなります。まずはシンボリックリンクを作成します。

sudo ln -s /usr/bin/rclone /sbin/mount.rclone

次にマウントユニットファイルを作成します。記述内容とファイル名はRcloneの公式ページの内容を参考にして、環境に合わせて書き換えます。実はこのファイル名は後で書きますが間違っています。

sudo nano /etc/systemd/system/home-mamu-stable-diffusion-webui-outputs.mount
[Unit]
Description=Mount for /home/mamu/stable-diffusion-webui/outputs
After=network-online.target

[Mount]
What=dropb:stableout
Where=/home/mamu/stable-diffusion-webui/outputs
Type=rclone
Options=rw,_netdev,allow_other,args2env,vfs-cache-mode=writes,config=/home/mamu/.config/rclone/rclone.conf,cache-dir=/var/rclone

[Install]
WantedBy=multi-user.target

ユニットファイル名とディレクトリパスの一致

なぜユニットファイル名とディレクトリパスを一致させる必要があるのか?

システムでユニットファイルを管理する際、ファイル名とその内容が一貫していることが重要です。これは、システムが自動的に正しいユニットファイルを見つけて適用するためです。ユニットファイル名とディレクトリパスを一致させることで、システムが正しいファイルを簡単に特定し、意図した通りに動作させることができます。

具体的な理由

  1. 一貫性の確保
    • ユニットファイル名とディレクトリパスを一致させることで、どのユニットファイルがどのマウントポイントに対応しているかを明確にします。管理が容易になり、誤解やミスを防ぐことができます。
  2. 自動認識
    • システムはユニットファイル名を使って自動的に適用するユニットを認識します。例えば、home-mamu-stable-diffusion-webui-outputs.mountという名前のユニットファイルは、/home/mamu/stable-diffusion-webui/outputsディレクトリをマウントポイントとして認識します。
  3. デバッグの容易さ
    • 問題が発生した場合、ユニットファイル名とディレクトリパスが一致していると、どのファイルに問題があるかを迅速に特定できます。トラブルシューティングが容易になります。

具体例での説明

例1:ユニットファイル名とディレクトリパスが一致している場合

  • ユニットファイル名: home-mamu-stable-diffusion-webui-outputs.mount
  • ディレクトリパス: /home/mamu/stable-diffusion-webui/outputs

この場合、システムはこのユニットファイルが/home/mamu/stable-diffusion-webui/outputsディレクトリをマウントするためのものであると自動的に認識します。

例2:ユニットファイル名とディレクトリパスが一致していない場合

  • ユニットファイル名: example.mount
  • ディレクトリパス: /home/mamu/stable-diffusion-webui/outputs

この場合、システムはどのディレクトリをマウントするべきかを正確に判断できず、設定ミスや動作不良の原因になります。さらにもう一つのオートマウントユニットファイルを作成します。こちらのファイル名も間違っているので後で説明します。

sudo nano /etc/systemd/system/home-mamu-stable-diffusion-webui-outputs.automount
[Unit]
Description=AutoMount for /home/mamu/stable-diffusion-webui/outputs

[Automount]
Where=/home/mamu/stable-diffusion-webui/outputs
TimeoutIdleSec=600

[Install]
WantedBy=multi-user.target

ここまで準備ができたらユニットファイルの変更を反映させるために、systemdデーモンをリロードします。

sudo systemctl daemon-reload

通常はオートマウントユニットを有効化するだけで十分ですが、手動でマウントユニットを有効化して起動することが必要な場合もあるかもしれません。オートマウントユニットを有効化して起動します。

sudo systemctl enable home-mamu-stable-diffusion-webui-outputs.automount
sudo systemctl start home-mamu-stable-diffusion-webui-outputs.automount

しかし、起動コマンドでエラーが発生しました。

Failed to start home-mamu-stable-diffusion-webui-outputs.automount: Unit home-mamu-stable-diffusion-webui-outputs.automount has a bad unit file setting.
See system logs and 'systemctl status home-mamu-stable-diffusion-webui-outputs.automount’ for details.

マウントユニットファイルに「cache-dir=/var/rclone」という記述があります。しかし、調べてみると無いので作成して、適切な権限を設定します。

sudo mkdir -p /var/rclone
sudo chown mamu:mamu /var/rclone

さらにエスケープシーケンスの問題があり、上記だけではエラーは解消されませんでした。

エスケープシーケンスとは?

エスケープシーケンスは、特定の文字や記号を正確に表現するための特別なコードです。特定の環境やプログラムで文字や記号を正しく解釈させるために使用されます。

なぜエスケープシーケンスが必要なのか?

Linuxシステムでは、ユニットファイル名にディレクトリパスを使用する際に、スラッシュ(/)やハイフン(-)などの特定の文字をエスケープシーケンスに変換する必要があります。これを理解しておくと、システムが正しいパスを理解し、適切に処理できるようになります。

エスケープシーケンスの具体例

ハイフンのエスケープ

ユニットファイル名でハイフン(-)を使用する場合、これをエスケープシーケンスに変換する必要があります。具体的には、ハイフン(-)はエスケープシーケンスで\x2dと表現されます。

例: ディレクトリパスとユニットファイル名の変換

例えば、ディレクトリパスが/home/mamu/stable-diffusion-webui/outputsの場合、このパスをユニットファイル名に変換する際には、ハイフンをエスケープシーケンスに変換します。

  • ディレクトリパス: /home/mamu/stable-diffusion-webui/outputs
  • ユニットファイル名: home-mamu-stable\\x2ddiffusion\\x2dwebui-outputs.mount

Windowsとの違い

Windowsでは、エスケープシーケンスの概念があまり一般的ではありません。Windowsのファイルシステムでは、ユニットファイルやマウントポイントの概念が異なるため、エスケープシーケンスを使用する必要がない場合が多いです。しかし、Linuxではファイルパスやユニットファイル名に特定の文字を含める際にエスケープシーケンスを使用することが必要です。

まとめ

エスケープシーケンスは、特定の文字や記号を正確に表現するための特別なコードです。Linuxシステムでユニットファイル名をディレクトリパスに変換する際には、スラッシュやハイフンなどの特定の文字をエスケープシーケンスに変換する必要があります。これでシステムが正しいパスを理解し、適切に処理できるようになります。

具体的には、ハイフン(-)はエスケープシーケンスで\x2dと表現されるため、ディレクトリパス/home/mamu/stable-diffusion-webui/outputsはユニットファイル名home-mamu-stable\\x2ddiffusion\\x2dwebui-outputs.mountに変換されます。

このようにして、ユニットファイル名とディレクトリパスを一致させることで、システムが正しくユニットファイルを認識し、適用することができます。これを考慮すると以下が正解です。

ファイル名がそれぞれ以下のようになります。

home-mamu-stable\x2ddiffusion\x2dwebui-outputs.mount
home-mamu-stable\x2ddiffusion\x2dwebui-outputs.automount

これを踏まえるとサービスの有効化と起動も以下になります。

sudo systemctl enable home-mamu-stable\\x2ddiffusion\\x2dwebui-outputs.automount
sudo systemctl start home-mamu-stable\\x2ddiffusion\\x2dwebui-outputs.automount

エスケープシーケンスはユニットファイル以外でもさまざまな状況で必要になることがあります。以下に、エスケープシーケンスを注意すべき一般的なケースをいくつか挙げます。

一般的なケース

1. シェルスクリプトやコマンドライン

シェルスクリプトやコマンドラインで特定の文字をエスケープする必要がある場合があります。例えば、スペース、アスタリスク(*)、ドル記号($)などの特殊文字はエスケープが必要です。

例: スペースを含むディレクトリ

mkdir "My Folder"
cd My\ Folder

2. 正規表現

正規表現では、メタキャラクター(.*?[]など)をエスケープする必要があります。

例: ドットをリテラルとして扱う

grep "example\.com" file.txt

3. プログラム言語

プログラミング言語(Python、JavaScriptなど)でも、文字列内で特殊文字をエスケープする必要があります。

例: Pythonでのエスケープ

path = "C:\\Users\\name\\Documents"

4. URLエンコード

URL内で特定の文字をエスケープする必要があります。例えば、スペースは%20にエンコードされます。

例: URLエンコード

https://www.example.com/search?q=hello%20world

5. SQLクエリ

SQLクエリで特殊文字をエスケープすることが必要です。特に、シングルクォート(')を含む文字列リテラルの場合です。

例: SQLクエリでのエスケープ

SELECT * FROM users WHERE name = 'O''Reilly';

ユニットファイル以外でのエスケープシーケンスの使用例

1. シェルスクリプトでの例

#!/bin/bash
echo "This is a backslash: \\"
echo "This is a new line character: \n"

2. 正規表現での例(Bash)

echo "The quick brown fox" | grep "quick\ brown"

3. Pythonでの例

# ファイルパスのエスケープ
path = "C:\\Users\\name\\Documents\\file.txt"

# 特殊文字のエスケープ
text = "This is a double quote: \" and this is a single quote: \'"

まとめ

エスケープシーケンスは、特定の文字を文字通りに扱うためや、特定の文字の意味を変えるために必要です。シェルスクリプト、正規表現、プログラミング言語、URLエンコード、SQLクエリなど、さまざまな状況でエスケープシーケンスを使用する必要があります。コードやコマンドが期待通りに動作し、エラーや予期しない動作を防ぐことができます。

教育

Posted by admin