ADR-0002: 同一性は workspaceId と sessionId で表し、名前は表示用のラベルに落とす¶
- 状態: Accepted
- 日付: 2026-08-21
- 関連: ADR-0001、ADR-0003(決定 5 の根拠 3 を差し替え)、
docs/design.md§2.1 / §4.2 / §4.4 / §9.3 / §9.6、bin/ccsのresolve_as_scratch/dir_is_empty/path_is_scratch_slot/registry_file_for_slug/pane_session_id_for/orphan_slots - 覆すもの: 無し。ADR-0001 の続きで、あちらが決めた「ディレクトリの同一性とセッションの 名前を分離する」を、どう表現するかまで具体化する。ADR-0001 の根拠にある 「空であること」という言い回しだけは、意味を変えずに精密化する(→ 決定 4)
- 実装: 本 ADR では行わない。
bin/ccsは触らない
文脈¶
セッションの名前は人が変える。 ccs で立てたあと、Remote Control 上で分かりやすい名前に
書き換えて長時間使う。ところが ccs は同一性を名前と枠番号から推論している。
いま、同一性はどこで推論されているか¶
| # | 箇所 | 何を同一性の根拠にしているか | 名前が変わると |
|---|---|---|---|
| 1 | resolve_as_scratch |
cc/tmp-N という tmux があるか |
稼働中の枠が「空き」に見え、横取りされる |
| 2 | resolve_as_scratch |
dir_is_empty(枠が空か) |
中身の残った枠は二度と配られない(ADR-0001 の (c)) |
| 3 | orphan_slots(ccs gc) |
1 と 2 の組み合わせ | 稼働中の枠を「孤児」として報告する |
| 4 | list_slugs |
tmux 名の cc/ 接頭辞以降 |
slug が変わる。cc/ を外されると一覧から消える |
| 5 | registry_file_for_slug |
レジストリの tmux を cc/<slug>: で前方一致 |
元の slug で引けなくなる |
| 6 | collect_session_row |
同上 | 引けなければ status が stopped になる |
| 7 | pane_session_id_for |
pane_start_command の中の --session-id <uuid> |
— (名前ではなく起動コマンドに依存) |
| 8 | path_is_scratch_slot |
scratch root の直下 + 空 | — (後述の印と正面から衝突する) |
| 9 | path_is_ccs_worktree |
worktree root 配下 + 解決時の変数 CCS_RESOLVED_WORKTREE_REPO |
— (実パスで指すと判定できない) |
| 10 | resolve_as_worktree |
パスの組み立て <root>/<repo>/<branch> だけ |
— (ディレクトリ側に印が無い) |
| 11 | cmd_new の冪等性 |
同一 slug の tmux があるか | 同じ作業ツリーに 2 本目の claude が立つ |
5 と 6 には未検証が残る。 レジストリの tmux フィールドが tmux 側の改名に追従するのか、
claude の起動時に書かれたきりなのかを確かめていない(手元の全セッションで両者は一致していたが、
枠 4/6/8 は改名の後に手で立て直されているので、どちらの説明でも同じ観測になる)。
どちらであっても「名前で照合するのは当てにならない」という結論は変わらないので、この ADR の
判断には効かない。確かめるなら tmux rename-session の前後でレジストリの tmux を読む。
11 は枠の話ではない。ccs new x01 で立てたセッションを cc/x01-refactor に改名すると、
次の ccs new x01 は「無い」と判断して同じリポジトリにもう 1 本立てる。冪等性
(design.md §4.3)が名前の付け替えで崩れる。
実測: 名前は実際に変わっている(2026-08-21、手元の 18 セッション)¶
| tmux セッション名 | claude の name |
formerNames |
cwd |
|---|---|---|---|
cc/equipment |
equipment |
— | ~/.cc-scratch/4 |
cc/wifi-diag |
wifi-diag |
— | ~/.cc-scratch/6 |
cc/contacts |
contacts |
— | ~/.cc-scratch/8 |
cc/tmp-2 |
[ccs] 朝会夕会 |
tmp-2 |
~/.cc-scratch/2 |
cc/cost-management |
[ccs] コスト分析改善 |
[ccs] cost-management, cost-management |
~/ghq/…/cost-management |
cc/ccs |
[ccs] ccb |
[ccs] ccd, ccs |
~/ghq/…/ccs |
tmux の名前と claude の名前は、別々に、何度でも変わる。 前者が変わったのが枠 4/6/8、
後者が変わったのが tmp-2 と cost-management と ccs。ccs は前者を同一性に使い、
人は後者を「分かりやすい名前」として使っている。
枠 4/6/8 は resolve_as_scratch の占有判定(#1)から外れる。ccs new --tmp に横取り
されるのを防ぐため、人が手でダミーファイルを置いた(ADR-0001 の運用メモ)。その中身は
こうだった。
# 枠 4: 備品管理(Notion 📒 DB_備品管理台帳)
tmux: `cc/equipment` / 会話: 45299e77-9a36-4c18-8e99-fe17915ae5d9
戻すには: `cd ~/.cc-scratch/4 && claude --resume 45299e77-9a36-4c18-8e99-fe17915ae5d9`
単に非空にするためのダミーではない。 置かれていたのは「このディレクトリは何で、どの 会話のもので、どう戻すか」という印そのものだった。運用が自然発生的にこの形を選んでいる。
逆方向(ディレクトリ → 素性)が引けない¶
~/.cc-scratch/6 を見ても、それが ccs の発行したものか、人が手で作ったものか、いつ誰が
発行したのかが分からない。ccs gc が「中身の残った枠」として報告できるのはパスだけで、
そこから先は人が中を読むしかない。ADR-0001 で枠が ~/.cc-scratch/<一意な名前> になると、
数字ですらなくなるので、この問題は今より効いてくる。
sessionId は改名にも再起動にも耐える(実測)¶
- 上の表のとおり、
nameが 2 回変わってもsessionIdは同じままで、旧名はformerNamesに残る - 枠 4/6/8 の
pane_start_commandはclaude -n <名前> --resume <uuid>だった。手で 立て直されている。 それでもレジストリのsessionIdは--resumeに渡した uuid と一致する ccsを claude セッションの中から呼ぶと、環境にCLAUDE_CODE_SESSION_IDがあり、 呼び出し元のレジストリのsessionIdと一致する(このセッションで確認:47f73f31-76cd-4ca3-9cd1-e76112500b51)
再現:
tmux list-panes -t cc/equipment -F '#{pane_start_command}'
jq -r '[.sessionId,.name,(.formerNames//[]|map(.name)|join(",")),.cwd]|@tsv' ~/.claude/sessions/*.json
printf '%s\n' "$CLAUDE_CODE_SESSION_ID" # claude の中から実行したとき
同時に、sessionId は「場所の同一性」ではない。 枠 4/6/8 は一度死んで別プロセスとして
立ち直っている。手で claude(--resume なし)を打てば、同じディレクトリに別の
sessionId が生まれる。1 つの作業ディレクトリに対し、会話は時間軸上で複数あり得る。
印を置くと「空であること」と衝突する¶
ADR-0001 は自動承認の根拠をこう書いた。
枠は
ccs自身が作ったディレクトリで、渡すのは空だと確かめたときだけ。つまり信頼確認が 守ろうとしている「知らないコード」がそこには存在せず、確認は情報を増やさない。
path_is_scratch_slot() は実際に dir_is_empty を見ている。印を置いた瞬間に、その
ディレクトリは自動承認されなくなる。 印と空判定の関係を決めない限り、この ADR は
ADR-0001 と正面から衝突する。
決定¶
1. 同一性は 2 層。workspaceId(場所)と sessionId(会話)に分ける¶
| 層 | 発行者 | 変わるか | 何を指すか |
|---|---|---|---|
workspaceId |
ccs |
発行から削除まで不変 | その作業ディレクトリ |
sessionId |
Claude | 会話ごとに不変(改名・--resume に耐える) |
その会話 |
slug / tmux 名 / claude の name |
ccs が初期値を置き、人が変える |
いつでも | 表示用のラベル |
名前は同一性の根拠にしない。 どの判定も、名前ではなく上の 2 つ(または作業ディレクトリの 実パス)で行う。
sessionId だけを同一性の正にはしない。1 つの作業ディレクトリに会話は複数ありうる
(実測: 枠 4/6/8 は手で立て直されており、--resume を使わなければ別 uuid になっていた)。
会話 id を場所の id に使うと、2 本目の会話が始まった瞬間に嘘になる。
workspaceId は ccs が発行する不透明な識別子で、ディレクトリ名そのものに使う
(~/.cc-scratch/<workspaceId>)。長さは小文字 16 進 8 桁とする。衝突は mkdir の失敗で
検出して引き直す。中身を解釈してはならない — 意味を持たせると、また名前から推論する
道が開く。
2. 発行したディレクトリには、ccs が印を刻む¶
ccs が作った使い捨て作業ディレクトリの直下に .ccs.json を 1 つ置く。
{
"schema": 1,
"workspaceId": "3f9a2c1b",
"kind": "scratch",
"issuedAt": "2026-08-21T09:12:34Z",
"issuedBy": {
"ccs": "0.3.0",
"host": "asakusa-t",
"sessionId": "47f73f31-76cd-4ca3-9cd1-e76112500b51"
},
"issuedSlug": "tmp-3f9a2c1b",
"issuedSessionId": "c56885d3-6808-4eb1-bd7b-5d39817ac670"
}
印には不変な事実だけを書く。 現在の名前・現在の sessionId・状態(running / idle)は
書かない。書けば更新が要り、更新が要るものは必ず腐る — それがいま名前で起きていること
そのものである。issuedSessionId は「発行時にこの uuid で起動した」という履歴であって、
「いまこの会話のものだ」ではない。
issuedBy.sessionIdは、ccsを呼んだのが claude セッションのときだけ入る (CLAUDE_CODE_SESSION_ID。実測で取れることを確認済み)。人が端末から打ったときはnull- 形式は JSON。
jqは既に必須依存なので、依存は増えない
3. 照合は名前ではなく作業ディレクトリで行う¶
占有も冪等性も、そのディレクトリを cwd にしている生きたセッションがあるかで判定する。
- レジストリの
cwdを使う(live_cwd_forが既に読んでいる)。registry_is_liveで pid の生存も見る(ADR-0001 決定 3 の具体化) - 比較は
abs_dirを通した実パスどうしで行う。/tmp→/private/tmpの正規化を 忘れると当たらない(design.md §6 と C1 で 2 度踏んでいる) - 削除・再発行の可否を決めるときは、cwd がそのディレクトリ配下にある場合も占有と見なす (安全側に倒す)
- 冪等性(#11)も同じ判定に移す。同じ作業ツリーに 2 本目を立てないことが目的であって、 同じ名前を返すことが目的ではない。既存が見つかったら、改名後の tmux 名をそのまま返す
4. 自動承認の条件を「空」から「ccs が作り、印以外に何も無い」に置き換える¶
path_is_scratch_slot() の判定を次に変える。
- scratch root の直下である
.ccs.jsonが読めて、kindがscratchで、workspaceIdがディレクトリ名と一致する- その印以外に何も無い
これは ADR-0001 の決定を覆さない。ADR-0001 が守ろうとしたのは「信頼確認が守るべき
『知らないコード』がそこに無い」ことで、「空であること」はその代理指標だった。
ccs 自身が書いた印は「知らないコード」ではないので、代理指標を直接の条件に置き換える。
判定は今より厳しくなる。 2 が加わるので、scratch root の直下に人が手で作った空 ディレクトリは自動承認されなくなる。安全側への変化なので受け入れる。
書く順番は「mkdir → 印を書く → ensure_trust → 起動」。順番で辻褄を合わせる案は採らない
(→ 捨てた案)。
5. worktree と ghq 配下には印を置かない¶
- git の作業ツリーを汚さない。
.ccs.jsonはgit statusに出て、コミットされ得て、 clean 判定を壊す - worktree は git 自身が素性を持っている。
git rev-parse --git-common-dirで元の リポジトリが引け、git worktree listで一覧が引ける。~~パスも<CCS_WORKTREE_ROOT>/<repo-slug>/<branch-slug>で素性を語る(design.md §9.6)~~ - したがって worktree に必要なのは決定 3(cwd で照合)だけで、印は要らない
根拠 3 を差し替えた(2026-08-26、ADR-0003)。結論は変わらない。 worktree の置き場所が
<repo>/.worktrees/<branch-slug>になり、CCS_WORKTREE_ROOTは 消えるので、「パスが素性を語る」は成立しなくなる。代わりに素性はgit rev-parseから 直接引く(ADR-0003 決定 3)── 規約を読むのをやめて実体に訊くので、根拠 1 と 2 は むしろ強くなる。印を置かないという結論はそのまま維持する。
path_is_ccs_worktree は今のまま(元リポジトリが ghq 配下なら信頼)。印の有無は関係しない。
6. ccs は自前のレジストリを持たない¶
「このディレクトリはどのセッションのものか」は、Claude のレジストリが cwd として既に
持っている(実測で全セッションに入っている)。ccs 側に索引ファイルを作ると、
ディレクトリと索引の 2 箇所を同期する必要が生まれ、必ずずれる。design.md §2.1 の委譲方針を
維持する。
印は「状態」ではないので、この方針と衝突しない。 design.md §9.3 が devas.life 版の
@claude_state を退けたのは「状態を hook で書く」ことに対してで、そこで置いてよいとしたのは
「ccs 自身が作った出自情報」だった。印はまさに後者で、しかもセッションではなく
ディレクトリと同時に消えるので、後片付けの対象が増えない。
追記(2026-09-02、R6 / #97):
ccs restore --pick が「選ばれなかった会話」を CCS_DISMISSED_FILE に記録する。
これもこの決定に反しない。ここが禁じたのは存在を二重に持つこと ── レジストリが
既に持っている事実を写して、ずれることだった。記録が持つのは他のどこにも無い人の判断
(この会話はもう終わっている)で、会話ログにもレジストリにも印にも書かれていない。
写しではないので、ずれる先が無い。
代わりに、写しではないものが残り続ける問題は引き受ける。だから
(a) 書き込みのたびに、会話ログが消えた行を落とす、(b) 戻したら記録を消す、
(c) 消せば全部やり直せる(rm してよい)。
7. 孤児の扱い¶
「印はあるが、そのディレクトリを cwd にする生きたセッションが無い」状態を孤児と呼ぶ。
| ディレクトリの状態 | 扱い |
|---|---|
| 印あり + 印以外に何も無い + 生きたセッション無し | ccs gc -y が消す |
| 印あり + 中身あり + 生きたセッション無し | 報告だけ。消さない(ADR-0001 の「利用者のファイル」の原則を維持)。報告には issuedAt / issuedSlug / issuedSessionId を添える |
| 印あり + 生きたセッションあり | 触らない |
印が無い / 壊れている / workspaceId がディレクトリ名と食い違う + 空 |
ccs のものと見なさないが、空なら消す(2026-09-05 に改定。下記) |
印が無い / 壊れている / workspaceId がディレクトリ名と食い違う + 中身あり |
触らない。「素性の分からないディレクトリ」として報告する |
改定(2026-09-05、#91):
元の表は決定 8 と食い違っていた。 ここは「印が無いものは触らない」と書き、決定 8 は
レガシー枠({1..8})について「今までどおり扱う(空なら rmdir)」と書いていた。
実装は安全側(この表)を採っていたが、その結果レガシー枠は空になっても永久に残る
── I2b 以降は番号の枠を発行しないので、畳んだあとは誰も触らない。
決定 8 側へ倒した。 判断は「ゴミが溜まり続けるほうが害が大きい」(#91、Ken)。
代償は明示して受け入れる: 人が手で作った空ディレクトリも消える。 ただし消えるのは空のときだけなので、失うのは「そこに何かを置くつもりだった」という 意図だけで、置いたものは失わない。
名前で素性を推定する案(^[0-9]+$ だけ消す)は採らない。 この ADR が一貫して
否定してきた形(名前を素性の根拠にしない)に戻ってしまうため。
印を失っても安全側に倒れる。 消えたら「ccs のものではない」と見えるだけで、勝手に
消されることも、勝手に信頼されることもない(決定 4 の条件 2 が効く)。
補助として、~/.claude/projects/<エンコードした cwd>/ にディレクトリ名が残る
(実測: ~/.cc-scratch/2 → -Users-apple--cc-scratch-2)。印を手で消されても、
transcript 側から workspaceId を逆引きできる。
8. 既存の ~/.cc-scratch/{1..8} には、遡って印を打たない¶
- 発行時刻も発行元も分からない。 印に書けば捏造になる。素性が分からないこと自体が 記録すべき事実なので、印の無いディレクトリとして扱う(決定 7 の最終行)
- 数字名のディレクトリは「レガシー枠」として扱う。新規発行はしない
(
resolve_as_scratchは印つきの新しいディレクトリしか作らず、返さない) - 移動しない。
~/.cc-scratch/legacy/4のような退避は、そこを cwd にしている稼働中の セッションを壊す(枠 4/6/8 は今も動いている) - レガシー枠の生死は決定 3 で見る。これだけで枠 4/6/8 の誤判定は消える
ccs gcはレガシー枠を今までどおり扱う(空ならrmdir、非空なら報告だけ)。人が 片付ければ自然に消える ── 決定 7 と食い違っていたが、2026-09-05 にこちら側へ揃えた(#91)。 ただし「レガシー枠だから」ではなく「印が無くて空だから」消す ── 名前で素性を推定しないため、結果として人が手で作った空ディレクトリも消える
ダミーファイル(~/.cc-scratch/{4,8}/SESSION.md)は、決定 3 が実装に入るまで消さない。
先に消すと、いまの名前ベースの判定では枠が空と見えて横取りされる。
根拠¶
なぜディレクトリの中に印を置くのか(索引ファイルではなく)¶
3 つある。
- 寿命が一致する。 印はディレクトリと同時に生まれ、同時に消える。索引は消えた ディレクトリの残骸を持ち続け、手で作られたディレクトリを知らないままになる。 孤児を掃除する仕組みが、孤児を作る仕組みになる
- 持ち運べる。 ディレクトリを見れば素性が分かる、が要求そのもの。索引は「どの索引を 見ればいいか」を先に知っている人にしか答えない
- 運用が既にそれを選んでいた。 人が手で置いた
SESSION.mdは、まさに印だった。ccsがやるべきなのは、それを機械可読にして、置き忘れをなくすことである
なぜ workspaceId をディレクトリ名に使うのか¶
ディレクトリ名に意味のある文字列(equipment など)を置くと、名前から推論したくなる。
それがこの ADR で潰している問題そのものなので、名前は不透明にして「読んでも何も分からない」
状態にする。分かりやすい名前が欲しい人は、いままでどおり tmux と claude の名前を変える。
8 桁にするのは、パスが ~/.claude/projects/ のエンコード名や transcript のパスにも現れる
ため。uuid の 36 文字は長すぎ、衝突は mkdir で確実に検出できる。
なぜ「空」ではなく「印以外に何も無い」なのか¶
ADR-0001 の根拠を読み直すと、条件は 2 つ書かれている。
枠は
ccs自身が作ったディレクトリで、渡すのは空だと確かめたときだけ
守っているのは前半(ccs が作ったこと)で、後半(空)はそれを外から確かめる手段だった。
印は前半を直接確かめられるようにする。 代理指標を捨てて直接の条件を見るので、
論拠はむしろ強くなる。
捨てた案¶
| 案 | 捨てた理由 |
|---|---|
sessionId を唯一の同一性にする(当初案) |
1 ディレクトリに会話は複数ありうる(実測: 枠 4/6/8 は手で立て直されている)。会話 id を場所の id に使うと、2 本目の会話が始まった時点で嘘になる。発行時の sessionId は印に履歴として残す |
ccs 側の索引ファイルだけで完結させる(~/.cc-scratch/index.json など) |
ディレクトリと索引の同期が要り、必ずずれる。孤児の掃除役が孤児を作る。design.md §2.1 の委譲方針にも反する。ただし将来の併用は否定しない(→ 未決) |
| tmux のユーザオプションに持つ(§9.3 のラベルと同じ場所) | セッションと同時に消えるのが利点だが、孤児の素性を答えるという要求がまさに「セッションが死んだ後」の話なので、根本的に足りない。生きている間の補助としては有効(→ 未決) |
| 印を起動の後に書き、空判定の順番で辻褄を合わせる | 順番に依存した暗黙の不変条件になる。誰かが順番を変えた瞬間に壊れ、しかも壊れ方が「勝手に信頼される」なので危ない。条件そのものを直す |
worktree にも .ccs.json を置く |
git の作業ツリーが汚れる(git status に出る・コミットされ得る・clean 判定が壊れる)。worktree の素性は git が既に持っている |
名前の付け替えを禁じる / ccs が名前を書き戻す |
改名は分かりやすさのために行われていて、それ自体は正しい運用。道具が人の運用を制約する側に回っているのが今の問題なので、逆向きに直す |
| 既存の 8 枠に遡って印を打つ | 発行時刻も発行元も分からず、書けば捏造になる。素性が不明であること自体が事実 |
影響¶
コード(別 PR。本 ADR では触らない)¶
resolve_as_scratch—workspaceIdを発行し、ディレクトリを作り、印を書く。空き枠探索は消えるpath_is_scratch_slot— 決定 4 の 3 条件に置き換える。名前はpath_is_fresh_scratchなどへdir_is_empty— 占有の推論に使うのをやめ、「印以外に何も無いか」を見る関数に寄せる- cwd で照合する関数を足す(
live_session_for_dir相当)。cmd_newの冪等性判定(#11)、resolve_as_scratchの占有判定(#1)、orphan_slots(#3)がこれに乗り換える orphan_slots— 枠番号のループをやめ、scratch root を走査して決定 7 の 4 分類で返すcmd_gc— 分類が 3 種から 4 種に増える(印なしの「素性不明」が加わる)。報告にissuedAt/issuedSlug/issuedSessionIdを出すls --json—workspaceIdを足す候補(ROADMAP の C3 と同じ枠)。既存フィールドは変えないpane_session_id_for(#7)— 手で--resumeした場合に uuid を拾えない問題はこの ADR では 直さない。印のissuedSessionIdがあれば「発行時の会話」は引けるが、手で別の会話に 差し替えられた場合は追えない。決定 3 とは独立の話- コメントに ADR-0002 を参照させる(README の規律)
ドキュメント¶
いま直すもの(古い理由が残ると、次に読む人が同じ前提から議論を始めるため)。
docs/adr/README.mdの一覧表に ADR-0002 を足すmkdocs.ymlの nav に ADR-0002 を足すdocs/design.md§4.2 — 「新しい名前の形は実装時に決める」と書いてある箇所から、 同一性の表現は ADR-0002 で決まったことへ導線を張るdocs/design.md§4.4 — 自動承認の条件が「空」から変わることを注記し、ADR-0002 へ送るdocs/adr/0001-scratch-workspace-identity.md— 関連に ADR-0002 を足す(決定は覆っていない ので状態は Accepted のまま)
実装が変わってから直すもの。 先に書き換えると、動くものと文書が食い違う。
docs/tutorial.md/docs/hands-on.md/docs/why.md/docs/agent-tools.mdのtmp-Nbin/ccsのusage()とdocs/img/help.svgdocs/configuration.mdのCCS_SCRATCH_SLOTSの説明
運用¶
~/.cc-scratch/{4,8}/SESSION.mdは、決定 3 が実装に入るまで消さない(先に消すと横取りされる)- 実装後、印のあるディレクトリは
cat ~/.cc-scratch/<id>/.ccs.jsonで素性が引ける - レガシー枠(1〜8)は人が片付けるまで残る。
ccsは空のものだけrmdirする
未決¶
以下は本 ADR では決めない。実装時に決めて、必要なら別 ADR にする。
- 印のファイル名。
.ccs.jsonの 1 ファイルか、.ccs/workspace.jsonのディレクトリか (後者は将来の追加物を入れられるが、いま入れるものが無い) ccsが自分の素性を答えるコマンド(ccs whoami/ccs id)を足すか。セッションの中から 「自分はどの workspace か」を引けると便利だが、cat .ccs.jsonで足りる可能性がある- 生きている間の補助として tmux のユーザオプション(
@ccs_workspace_id)にも持つか。 C2 のラベルと同じ場所だが役割が違う(あちらはccb用の不透明な文字列) - hub home(
~/.cc-hub)に印を打つか。 場所が固定で 1 つしか無いので不要と考えているが、 害も無い - worktree の印を
.git/worktrees/<name>/に置くか。 git の管理領域なのでgit statusに 出ず、git worktree removeで一緒に消える。決定 5 を保ったまま素性を持たせられるが、 印の置き場所が 2 種類になる CCS_SCRATCH_SLOTSの去就(ADR-0001 から持ち越し)。同時に立てられる本数の上限として 残すか、廃止するかworkspaceIdの衝突時の再試行回数と、scratch root が別マシンと共有されていた場合の扱い (印のissuedBy.hostを見て拒むか、無視するか)