結城です。
先だって、当社のThunderbirdサポートにおいてお客様から以下のようなお問い合わせを頂きました。
- Thunderbird 140.5.0ESRが複数のメールフォルダーについて、ダウンロード済みであるはずのメールを、毎日再ダウンロードする。その結果、ローカルのプロファイルフォルダーのサイズが1日あたり1~2GBずつ増加し、ハードディスクの空き容量が逼迫している。
- 現象は特定のユーザーでのみ発生している。
- Thunderbirdのプロファイルを再作成して全メールを受信完了させた後でも、現象は引き続き発生する。
- メールサーバー側には特にエラーログは記録されていない。
本稿執筆時点でも完全解決には至っていませんが、お客様のご協力を頂いての調査の結果、原因の一端と回避方法は判明しました。 今回は、同様のトラブルでお悩みの方の参考になるよう、本件について現時点で分かっていることをご紹介します。
はじめに:回避方法
まず現時点で判明している回避方法を紹介しますが、その前に、「同様のトラブルで困っていて、とにかく回避方法を探している」という方に向けて、注意事項があります。
- 今回のトラブルは、以下の条件で発生しています。条件が異なる場合は別の原因である可能性が高く、この回避方法は有効に作用しないと考えられます。
- 当該メールアカウントの「サーバーの種類」が「IMAPメールサーバー」である。
- 当該メールアカウントの「メッセージの格納形式」が「フォルダー単位(mbox形式)」である1。
- メールのダウンロードが何度も行われているフォルダーのプロパティを開き「一般情報」タブを見ると、「メッセージ数」は変化しておらず、「ディスク上のサイズ」の数字だけが増えている。
- この回避方法を実施した場合、「メール本文が途中で切れて見える」トラブルの発生頻度が上がる恐れがあります。
- 安全のためには、社内LANのように安定したネットワークを経由してメールサーバーと通信できており、通信の意図しない途絶などが滅多に発生しない状況で使用するようにしてください。インターネットのように不安定なネットワーク経由でメールサーバーと通信している場合には、この回避方法は非推奨です。
以上の事を踏まえての、本件トラブルの回避方法は以下の通りです。
- Thunderbirdの設定画面(メニューバーの「ツール」→「設定」、または アプリケーションメニューの「設定」)を開く。
- 「一般」タブで、最下部までスクロールして表示される「設定エディター」ボタンをクリックする。
- 開かれたタブの「設定名を検索」欄に
mail.discard_offline_msg_on_failureと入力する。 - 表示された行について、値が
trueかどうかを確認する。trueであれば、行をダブルクリックして値をfalseに変更する。
この設定変更により、Thunderbirdはメール本文の再ダウンロードを行わなくなります。
この設定はその名前の通り、「メール本文のダウンロードに失敗した場合に、ローカルにダウンロード済みのメール本文データを破棄して、再ダウンロードの対象とする」ための物です。 設定を変更することにより、副作用として「メール本文のダウンロードが回線の不調で意図せず中断されてしまったため、本文が途中までしか表示されない」といったトラブルが発生するようになる恐れがあります。 もしそのような状況が発生した場合は、安定したネットワークに接続している状態で、当該メールが含まれるメールフォルダーのプロパティを開いて「フォルダの修復」を手動で実行し、メール本文を強制的に再ダウンロードさせてください。
現象からの原因究明
ここからは、お問い合わせから回避方法の特定までに行った調査の経緯をご紹介します。
Thunderbirdに限らずですが、トラブル対応では、症状の再現条件を特定できているかどうか、症状をこちらの環境で再現できるかどうかによって打てる手が変わってきます。
症状をこちらの手元で再現できれば様々な角度から調査を行えるのですが、本件は当社の環境では現象を再現できませんでした。 このような場合、トラブルの原因を究明するためには、とにかく「お客さまの環境で実際には何が起こっているのか」を正確に把握する必要があります。
正確な状況を正しく知るためのログ採取
Thunderbirdの内部構造は、「UI部分」と「低レイヤー部分」の2つに大別できます。 ボタンが反応しない、メールを送信しようとして反応がなくなる、といった種類のインターフェースの応答性に関わるトラブルは、多くの場合UI部分で起こっています。 それに対して、メールが消える、ダウンロードに時間がかかるなど、通信処理やデータの取り扱いに関わるトラブルは低レイヤー部分で起こっていることが多いです。 本件も、「複数のメールフォルダーについて、ダウンロード済みであるはずのメールを再ダウンロードする」という症状から、トラブルは低レイヤー部分で起こっている可能性が高いと考えられます。
そこで今回は、環境変数 MOZ_LOG を用いた低レイヤーのログ出力機能を用いて、お客さまにご協力を頂き、現象が発生したときの詳細なログを採取して頂きました。
低レイヤーのログの採取にあたっては、対象モジュールを事前に明示する必要があります。
しかし、よく知らない部分の処理のログを採取しようと思うと、そもそもどのモジュールのログを採取すればよいのかが分からない、というジレンマが生じます。
そこで今回はまず、この時点ではIMAPアカウントかどうかも確定していなかったため、メールサーバーとの通信処理で使われる SMTP、POP3、IMAP の各モジュールと、メールフォルダーのデータの取り扱いでよく登場する、最適化処理のモジュール compact とメールフォルダー間のメールの移動やコピーのモジュール MsgCopyService を指定してログを採取し、その結果から関連性が疑われる他のモジュールを見付けていくことにしました。
これらのモジュールのログを出力する状態でThunderbirdを起動する手順は、コマンドプロンプトを使用する場合は以下の要領です。
> set MOZ_LOG=timestamp,sync,SMTP:5,POP3:5,IMAP:5,compact:5,MsgCopyService:5
> set MOZ_LOG_FILE=C:\Users\Public\log.txt
> "C:\Program Files\Mozilla Thunderbird\thunderbird.exe"
ログから現象発生時の状況を読み取る
前述の手順をお客さまにご案内してログを採取して頂いた所、メールのダウンロードが行われたことを示唆する物として以下のようなログを確認できました(※ホスト名やメールフォルダー名は実際の物とは異なります。また、実際は1行のログですが、ここでは見やすいように行頭の日時部分を省略し、改行もしています。以下、ログの例はすべて同様の加工を施しています)。
[Parent 15340: IMAP]: I/IMAP
1671923f800:example.com:S-INBOX.XXXX.XXXX.XXXX:STREAM:OPEN Size: 6340:
Begin Message Download Stream
このログからはまず、問題のメールアカウントはIMAPアカウントであることが分かります。
各ログに共通する文字列である Begin Message Download Stream を手がかりに、実際にダウンロードが発生したメールフォルダーのパスを示す部分を抽出して、その登場回数を数え上げてみた結果、以下のように1フォルダーあたり最大7回ダウンロードが発生している様子が窺えました。
$ cat log.txt.moz_log | grep "Begin Message Download Stream" | cut -d : -f 7 | sort | uniq -c
7 S-INBOX
1 S-INBOX.XXXX.XXXX.XXXX
1 S-INBOX.YYYY.YYYY
ただ、この回数は「フォルダーに新着メールがあったため何度もダウンロードが発生した」回数と「ダウンロード済みのはずのメールが何度もダウンロードされた」回数が混ざった結果で、「現象が起こったケース」を調査するにはまだ絞り込みが必要です。
そこでもう少しヒントが得られないかと個々の Begin Message Download Stream のログの後に出力されているログを見てみたところ、IMAP モジュールのログにはIMAPでの通信のリクエストとレスポンスがすべて現れており、以下のように、ダウンロードされたメールのヘッダーも含まれていることが分かりました。
[Parent 15340: IMAP]: I/IMAP
1671923f800:example.com:S-INBOX.XXXX.XXXX.XXXX:CreateNewLineFromSocket:
Message-ID: <XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX@example.com>
そこで、今度はフォルダー名と Message-ID の部分を抽出して重複を数え上げてみた結果、以下のように、確かに同じフォルダーに同じ Message-ID を持つメールが2回ダウンロードされているのが確認できました2。
$ cat log.txt.moz_log | grep ':CreateNewLineFromSocket: Message-ID:' | cut -d : -f 7,10 | sort | uniq -c | sort
1 S-INBOX.XXXX.XXXX.XXXX: <XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX@example.com>
2 S-INBOX: <AAAAAAAA-AAAA-AAAA-AAAA-AAAAAAAAAAAA@example.com>
2 S-INBOX: <BBBBBBBB-BBBB-BBBB-BBBB-BBBBBBBBBBBB@example.com>
2 S-INBOX: <CCCCCCCC-CCCC-CCCC-CCCC-CCCCCCCCCCCC@example.com>
なお、ログ採取時の状況説明として、お客さまからは以下の補足情報も頂くことができました。
- 再ダウンロードが発生するフォルダーは毎回一定していない。
- 再ダウンロード自体、発生したりしなかったりする。
要約ファイルとメールフォルダーの実体ファイルの調査
通常、ThunderbirdはIMAPメールサーバーに対して、「未受信のメールがないか」をメールフォルダーごとの STATUS コマンドで確認し、SELECT コマンドでその詳細を把握して、ローカルに未受信のメールがあれば FETCH コマンドで取得する、という動作を行います。
複数回のダウンロードが発生しているメールについてこれらのIMAPの通信の詳細を見た限りでは、メールはThunderbirdから「未受信のメール」として認識されていて、FETCH コマンドによって通常通りの流れでダウンロードされている様子でした。
このことから、現象を引き起こす原因はメールサーバー側にはなく、Thunderbird側での「どのメールをダウンロード対象とするか」の判断の部分にあると考えられました。
ところで、当初のお問い合わせでは「メールがフォルダーに何度もダウンロードされ、メールフォルダーが肥大化する」と説明を頂いていたものの、現象が
- フォルダー内に同じメールが増殖したように見える。
- フォルダー内に見えるメールの数は変わらず、ストレージの消費量だけが増えている。
のどちらであるかについては、言及を頂いていませんでした。
そこで改めてお客さまに確認した所、現象発生時の状況は後者に該当していると分かりました。 これは端的には、「メールフォルダーの実体と要約情報3との間に不整合がある」もしくは「実体ファイル内にゴミデータが蓄積されている4」状況と言えます。 そこで、メールが繰り返しダウンロードされて肥大化したメールフォルダーの実体ファイル(mbox形式)と、その要約ファイル(msf)を調査資料として採取して頂き、詳しい状況を事後的に調査してみました。
要約ファイルは morkdump というコマンドを使って内容を見ることができます。
出力結果と実体ファイルの内容を比較すると、以下の状況であることが分かりました。
- フォルダーの実体ファイル内には、バイナリーレベルで全く同じメールのデータが複数存在している。
- 要約ファイルからは、そのうちの最後の1つのみが有効なメールのデータとして参照されている。
- 複数ある他のデータは、どこからも参照されないゴミデータになっている。
- 要約ファイルを使わずに実体ファイルをThunderbirdに読み込ませて、実体ファイルから要約を再作成させる(「フォルダーの修復」を行う)と、隠れていた重複メールが見える状態になる。
- この状態においては問題のフォルダーには「削除済みフラグが立っているメール」が無い(重複しているメールに対応するヘッダー情報が要約内には存在しない)ため、「実際のメールフォルダーのサイズから、削除済みフラグが立っているメールのサイズの合計を引いた、最適化の余地があるデータ量」は0と判定されてしまう。
- そのため、「最適化で何MB以上のストレージ領域を開放できるなら」という条件での自動最適化が発動してくれない。
- 最適化を行う余地がないと判定されてしまうため、「フォルダーの最適化」を手動実行しても最適化が行われない。
つまり、実体ファイルと要約情報の間に、実装上検出できず見過ごされてしまう「不整合」が生じており、実体ファイル内に異常な量のゴミデータが蓄積されている、ということになります。
この現象が起こっているメールフォルダーをThunderbird上での操作で復旧するためには、
- 「フォルダーの修復」を実施して、不可視のメールを一旦可視状態にする。
- 可視状態になった重複メールを削除する。
- フォルダーを最適化する。
という手順を経る必要があります。 こちらのお客さまの環境では対象となるフォルダー数が多いことから、この対処は現実的ではなく、最初のお問い合わせ時点で頂いた情報も踏まえると、運用上は「時々Thunderbirdのプロファイルを再作成する」という形で対処されていたものと推測されます。
このような状況が何故発生するのかはこの時点では不明でしたが、メールフォルダーの操作を行うモジュール(FolderLockやMsgFolderCache)や、要約情報を管理するモジュール(MsgDB)の動作を見ることで、何かヒントが得られる可能性があります。
また、ここまでの調査の過程で、IMAPの処理を行うモジュールにはさらにいくつかのサブモジュール(IMAPAutoSync、IMAP_CS、IMAPCache、IMAP_DC、IMAP_KWなど)があることも分かりました。
そこで、ログ出力対象のモジュール指定にそれらを加えて以下のようにして、再度、現象発生時のログの採取をお客さまに依頼することにしました。
> set MOZ_LOG=timestamp,sync,compact:5,MsgCopyService:5,MsgDB:5,FolderLock:5,MsgFolderCache:5,IMAP:5,IMAPAutoSync:5,IMAP_CS:5,IMAPCache:5,IMAP_DC:5,IMAP_KW:5
詳細なログとソースコードから、より本質的な原因に迫る
以上のようにして再度採取して頂いたログで、多数のメールの再ダウンロードを行っている様子が窺える箇所を探したところ、以下のようなログが出力されていました。
[Parent 25296: Main Thread]: D/IMAPAutoSync ProcessExistingHeaders:
59 messages will be added into the download q of folder
imap://user@example.com/INBOX/XXXX/XXXX/XXXX
ログの固定文字列部分をThunderbirdのソースコードのオンライン検索サービスで検索すると、ログの出所となる実装箇所を特定できます。 このログの出所は、以下のようになっていました。
// process the existing headers and find the messages not downloaded yet
uint32_t lastIdx = mProcessPointer;
nsTArray<nsMsgKey> msgKeys;
uint32_t keyCount = mExistingHeadersQ.Length();
for (; mProcessPointer < (lastIdx + aNumOfHdrsToProcess) &&
mProcessPointer < keyCount;
mProcessPointer++) {
bool hasMessageOffline;
folder->HasMsgOffline(mExistingHeadersQ[mProcessPointer],
&hasMessageOffline);
if (!hasMessageOffline)
msgKeys.AppendElement(mExistingHeadersQ[mProcessPointer]);
}
if (!msgKeys.IsEmpty()) {
nsCString folderName;
folder->GetURI(folderName);
MOZ_LOG(
gAutoSyncLog, LogLevel::Debug,
("%s: %zu messages will be added into the download q of folder %s\n",
__func__, msgKeys.Length(), folderName.get()));
rv = PlaceIntoDownloadQ(msgKeys);
if (NS_FAILED(rv)) mProcessPointer = lastIdx;
}
コメントにまさに、「既知のヘッダー情報の中でまだダウンロードしていないメールを検出してダウンロードする」と書かれており、メールの再ダウンロードはここでの判断に基づいて行われていることが分かります。
そこで、誤判定が発生する可能性がないか調べるために、メールをダウンロード対象とするかどうかの判定を行っている folder->HasMsgOffline() の実装を見てみました。
// Looks like this implementation is only ever used for IMAP folders.
NS_IMETHODIMP nsMsgDBFolder::HasMsgOffline(nsMsgKey msgKey, bool* result) {
NS_ENSURE_ARG(result);
*result = false;
GetDatabase();
if (!mDatabase) return NS_ERROR_FAILURE;
nsresult rv;
nsCOMPtr<nsIMsgDBHdr> hdr;
rv = mDatabase->GetMsgHdrForKey(msgKey, getter_AddRefs(hdr));
if (NS_FAILED(rv)) return rv;
if (hdr) {
uint32_t msgFlags = 0;
hdr->GetFlags(&msgFlags);
// check if we already have this message body offline
if ((msgFlags & nsMsgMessageFlags::Offline)) *result = true;
}
return NS_OK;
}
実装を見ると、単純に、要約情報に保存されているフラグに nsMsgMessageFlags::Offline (メールがオフライン用にダウンロード済みかどうか、オフラインで読める状態かどうか)のビットが立っているかどうかだけで判断していると分かります。
そこで、受領した「現象が起こっているフォルダーの要約ファイル」の morkdump の結果をもう一度精査してみると、何度もダウンロードされた様子が窺える重複メールの項目については、確かに flags に offline が含まれていないことが分かりました。
それに対して、現象が起こっていない(重複したデータが含まれていない)フォルダーの要約ファイルや、手元のThunderbirdのIMAPフォルダーの要約ファイルを morkdump にかけてみると、こちらは flags に offline が含まれています。
このことから、何度も再ダウンロードされるメールは、メールをダウンロードした後に要約情報のフラグの nsMsgMessageFlags::Offline のビットが立てられていないか、もしくは nsMsgMessageFlags::Offline のビットが何らかの理由で後からクリアされていると考えられます。
メールの「ダウンロード済み」フラグが未設定になる条件を特定する
ここまでの調査結果から、より問題の本質に近いのは「メールの『ダウンロード済み』フラグが保存されない、あるいは失われている」ことの方で、「メールが何度もダウンロードされている」のはその結果起こっているに過ぎない、ということが言えます。
そこで今度は、メールに「ダウンロード済み」フラグが未設定となる場合としてどのような物があるかをソースコードから検索し、ログと突き合わせることで、現象発生時はどのコードパスを通っていたのかを明らかにしていきます。 この調査の過程でコードパスを変える条件分岐や設定項目が見つかれば、それを利用して現象の発生を回避できる可能性が出てきます。
nsMsgMessageFlags::Offline という定数を参照している箇所を検索して、結果をひとつひとつ調べてみたところ、いくつか「容疑者」がいることが分かりました。
容疑者の1人目は、当該フラグを立てたりクリアしたりする nsMsgDatabase::MarkOffline() というメソッドと、その呼び出し元の、メールのダウンロード完了時に実行されているらしい nsMsgDBFolder::EndNewOfflineMessage() という処理です。
ログには以下のようなメッセージが表れており、現象発生時にこの処理が実行されていたことは間違いないようです。
[Parent 25296: Main Thread]: I/FolderLock
[imap://user@example.com/INBOX/XXXX/XXXX/XXXX]
ReleaseSemaphore: nsMsgDBFolder::EndNewOfflineMessage
released the semaphore (1a7a1e92010)
コードを見ると、このログを出力したであろう箇所の直後で if による条件分岐を行い、その中で nsMsgDatabase::MarkOffline() を呼んでいます。
// Are we being asked to abort and clean up?
if (NS_FAILED(status)) {
mDatabase->MarkOffline(messageKey, false, nullptr);
if (m_tempMessageStream) {
msgStore->DiscardNewMessage(this, m_tempMessageStream);
}
return NS_OK;
}
この status は nsMsgDBFolder::EndNewOfflineMessage() に渡された引数で、どうもダウンロード処理の成否を示している様子なのですが、何か問題が起こったときに「ダウンロード済み」フラグをクリアするようになっているようです。
このメソッドの呼び出し元を調べてみると3箇所あり、2箇所はIMAPフォルダーの処理、1箇所はニュースグループの処理でした。
ニュースグループは無関係なのでIMAPフォルダーの方の処理だけ見てみると、1箇所目は「成功」の定数である NS_OK を渡していて本件とは完全に無関係、2箇所目は NS_ERROR_ABORT というエラーコードを渡していて本件との関連疑いありです。
そこでさらに2箇所目の呼び出し元を見てみた所、nsImapMailFolder::AbortMsgWriteStream() を経由して nsImapProtocol::AbortMessageDownLoad() での条件分岐の中から間接的に呼ばれていることが分かりました。
また、ここで Abort Message Download Stream という文字列を含むログを出力していたため、現象発生時のログ内を検索したところ、以下のようにログに表れているのを確認できました。
[Parent 25296: IMAP]: I/IMAP
1a7a32a6200:example.com:S-INBOX.XXXX.XXXX:STREAM:CLOSE:
Abort Message Download Stream
ただ、「ダウンロード済み」フラグをクリアする処理は、このログが出力された後にいくつかの条件分岐を経てから実行されるようになっており、このログがあるからといって「このコードパスでフラグがクリアされた」と断定することはできません。 また、現象発生時のログの中でこの文字列が現れる箇所は1箇所しかなかったり、複数回採取して頂いた別のログの中ではそもそも見つからなかったりしている点からも、「これが原因でいくつものメールの『ダウンロード済み』フラグがクリアされている」とは考えにくい状況です。
容疑者の2人目は、こちらも nsMsgDatabase::MarkOffline() の呼び出し元のひとつである、明示的にダウンロード済みメールを破棄する処理であることを示唆する名前の nsMsgDBFolder::DiscardOfflineMsg() という処理です。
このメソッドはIMAPのデータ受信処理のリスナーの通信終了時用のコールバックとオフライン時のメッセージ読み込み処理のリスナーの読み込み終了時用のコールバックの2箇所から呼ばれています。
このどちらの呼び出し元も、mail.discard_offline_msg_on_failure という設定の値が true であるときの分岐の中で nsMsgDBFolder::DiscardOfflineMsg() を呼んでいます。
ここまでで採取頂いたログからは、現象発生時にこのコードパスを通ったかどうかは判別できませんでしたが、もしここを通っていたのであれば、mail.discard_offline_msg_on_failure を false に切り替えれば「ダウンロード済み」フラグがクリアされなくなる可能性があります。
容疑の確定
以上の調査結果を踏まえ、
- まず
mail.discard_offline_msg_on_failureの値を切り替えて、現象が発生しなくなるかどうかを確認して頂く。(現象が依然発生するなら、この処理は容疑者から外れ、今後の調査対象から除外できる。) - 現象が依然発生し続ける場合、「ダウンロード済み」フラグに関わっている他の処理にも調査範囲を拡げ、ログ出力対象を増やしての再度のログ採取を依頼する。
という風に調査方針を立ててお客さまにご連絡したところ、「mail.discard_offline_msg_on_failure の値を切り替えたら現象が発生しなくなった」とのご連絡を頂くことができました。
このことを以て、本件については暫定回避策としてこの設定値の変更が有効だとの結論に至ったのでした。
まとめ
以上、Thunderbirdの運用上で発生した「メールが繰り返しダウンロードされてしまう」トラブルについて、回避方法が明らかになるまでに行った、ログやThunderbirdのソースコードを参照した調査の事例をご紹介しました。
本件の調査は、実際の運用環境上でログを採取頂く必要があったことから「待ち時間」となる期間が長く、最初のお問い合わせから回避方法の特定までに4ヵ月以上を要する大捕物となりました5。 お客さまからはこれ以上の調査のご依頼は頂いていないため、「外観上はメールは無事にダウンロードされたように見えているのに、内部的にはダウンロード失敗と判定されている」状況が発生する原因は、依然不明となっています。 とはいえ、同様の症状でお悩みの方にとっては有用な情報となるため、今回はこのような形で記事化してみた次第でした。
株式会社クリアコードは、FirefoxやThunderbirdの法人運用において生じた様々な問題について、ソースコードレベルの調査も含めたサポートを行うサービスを有償でご提供しています。 また、FirefoxやThunderbird自体の不具合が原因だった場合、開発元に報告を行い、可能な場合はパッチも提供しています。 FirefoxやThunderbirdの運用で何かお困りの企業の運用担当者さまは、お問い合わせフォームよりお問い合わせ下さい。
-
「メッセージ単位(Maildir形式)」が選択されている場合に同様のトラブルが発生するのかどうか、「メッセージ単位(Maildir形式)」を選択することが有効な回避方法として作用するのかどうかは、現時点では未調査のため不明です。 ↩
-
メールを手動操作などでコピーしたり、実態のメールアドレスとエイリアスの両方が宛先に設定されたメールを受信した場合などにも、
Message-IDの重複は起こり得ます。ただ、お客さまによると、このログの採取時にはメールの再ダウンロードが発生していたことを確認できていたとのことなので、ここではその可能性は除外しています。 ↩ -
メールアカウントの「メッセージの格納形式」が「フォルダー単位(mbox形式)」である場合、Thunderbirdはダウンロードしたメールのデータを、メールフォルダーと同じ名前のテキストファイルに追記していき、「各メールのデータがファイルの何バイト目から始まっているか」という情報を、各メールの件名や日付などの情報と併せて、メールフォルダーの名前の後に拡張子「.msf」が付いた「要約ファイル」に保存します。 ↩
-
mbox形式のフォルダーからメールを削除する場合、Thunderbirdは要約ファイルに「このメールは削除済みである」という情報を追加するだけに留めて、実体ファイルからはメールを削除しません。そうするとフォルダーの実体ファイルにはゴミデータが残留していくため、このゴミデータの量が一定量を超えたタイミングで、Thunderbirdは「フォルダーの最適化」を実施してゴミデータを一掃するようになっています。 ↩
-
当社側での実働時間はそれほど長くなかったため、調査工数としては2人日程度に収まっています。 ↩