← 목록
기타 2026-06-11 21KB 읽기 22분

crownyc 트윈 마이그레이션 마스터플랜 — 맵 729캡 근본해결

2026-06-11 · 아키텍트 종합 · 분석·계획 문서 (라이브 서비스/공유 crownyc 바이너리 무변경) 검증 기반: /Users/ef/CrownyOS/crownyc/crownyc.c 직접 독해 (5868~5929, 9066~9087, 2691~2716, 1567~1646, 1583~1619)

1. 문제·목표

문제 (소스 검증 완료)

crownyc VM의 해시맵은 고정 729엔트리 open-addressing 선형프로빙 평면배열이다.

위치사실결과
crownyc.c:5875맵생성(op412) heap_ptr -= 1458 (729 키-값쌍 고정)모든 맵이 정확히 729 슬롯
crownyc.c:5889 맵넣어(op413)for(hp<729){ hs=(hs0+hp)%729; hka=va-hs*2 }729 다 차면 루프 종료 → silent drop (체이닝/오버플로 없음)
crownyc.c:5894빈슬롯(hek==0) 만나야 삽입729 충돌 시 신규 키 조용히 유실
crownyc.c:5914 맵꺼내(op414)동일 729 프로빙, 못 찾으면 -1유실 키 영구 조회 불가
crownyc.c:9069·9074 맵키목록(op852)결과배열 1024 고정 + hk_count<1023 + 729 스캔상한>1023키는 추가 truncation (프로빙과 독립적 2차 손실)
crownyc.c:2701·2715 trit_hash_6트릿 접기 → 정확히 0..728 (3⁶) 반환729 캡의 수학적 근원, ISA729 729진 아키텍처 결속
실질 위협: 단일 맵이 ~729 엔트리 초과 시 상태 silent 손실. 맵히트맵 분석상 HIGH 위험 5종 — enterprise(670 맵생성×3457 맵넣어), church(451×2239), gateway(297×1001, 123서비스 레지스트리), finance(초대DB 12파티션으로 729 회피 중, 단일화 시 600+ 도달), aimed(11MB 데이터·3맵 분산). finance는 이미 invite-snap.p0~p11.dat 12-파티션 샤딩으로 캡을 수동 우회하고 있다 — 근본해결 아님.

목표

  1. 729캡 근본해결: 단일 맵이 용량을 자연증식(rehash-grow)하도록 VM 수술. 샤딩 같은 애플리케이션-레벨 우회 제거.
  2. 라이브 무중단: 33개 라이브 서비스를 멈추지 않고 점진 컷오버. 블라스트 반경을 카나리 1서비스로 제한.
  3. 후방호환 (3중 보장): 기존 toau 바이트코드 재컴파일 없이 new VM에서 동일 동작. 기존 .dat 무변환 로드.
  4. 원자성·롤백: mv rename 원자 스왑 + 구 바이너리 백업으로 즉시 복귀.

2. crownyc-next 설계 — 권장 접근 확정

확정 접근: "sized-at-creation + 동적 rehash-grow 하이브리드, open-addressing 유지"

체이닝(linked overflow)은 명시적으로 기각한다.

기각 근거 (체이닝): 현 구조는 맵핸들=주소, 슬롯이 핸들에서 va-hs*2로 아래로 펼쳐지는 순수 평면배열이다. 체이닝은 큐브 안에 next-포인터를 트릿 패킹해야 하고 → GC 힙스캔/문자열 remap/맵키목록/디스크 .dat 직렬화가 전부 포인터-추적으로 바뀐다. 수술 표면 폭발 + 후방호환 깨짐. open-addressing 유지 시 데이터 레이아웃 (키/값 인접쌍)이 보존돼 후방호환이 깨끗하다.

확정 접근 메커니즘:

  1. 용량 헤더 블록: 맵생성(op412)이 선택적 용량 인자(트라이트)를 받아 cap=올림(3^k) (기본 729) 슬롯 할당,
핸들 +1 (va+1, 위쪽) 메타슬롯에 cap 기록. 슬롯영역(아래쪽 va-hs2)과 절대 비충돌.
  1. cap-인지 프로빙: 맵넣어/맵꺼내/맵키목록의 729 하드코딩 상수를 메타슬롯 cap 읽기로 치환.
  2. rehash-grow (자연증식): 맵넣어 삽입 후 부하율 > cap*2/3 초과 시 → cap'=cap*3 새 블록 할당,
전 키/값 재해시 복사, 새 핸들 push 반환. 호출규약 무변화 — 이미 m = 맵넣어(m,k,v) 핸들-반환 패턴 존재 (5902).
  1. 해시 cap-투영: cap=729일 땐 현 trit_hash 분포 정확히 보존(0..728이 cap에 단순 포함). cap>729일 땐
k트릿(6→k) 접기 확장 또는 (hs0*상수)%cap 재투영. cap=729 폴백 시 분포 무변경이 후방호환 핵심.

heap 완화 (★2026-06-11 적대검증·소스재확인으로 정정★)

KILL-SHOT 정정: 초안의 "mem_ensure realloc로 MEM_DEFAULT→MEM_HARD_LIMIT 12M 여유" 주장은 거짓이다. crownyc.c:1567-1568 MEM_DEFAULT == MEM_HARD_LIMIT == 12000000 (동일 상수). 1576에서 부팅 시 calloc(12M) 즉시 할당, MEM_MAX=MEM_DEFAULT. mem_ensure(1610)는 n>MEM_MAX && n<=MEM_HARD_LIMIT일 때만 grow하나 둘이 같으므로 항상 거짓=성장 불능(dead code). 아레나는 부팅부터 12M 고정, 헤드룸 0. rehash-grow는 이 고정 아레나 안에서만 해야 한다.
  • map-of-maps 현실 (셀코어 새셀 56줄 = 맵생성): finance 초대DB는 맵의 맵이다. 셀 1개 = 자체 1458슬롯 내부맵.
외부맵 cap=729면 729 셀 × 1458 ≈ 1.06M 큐브(finance만으로 12M의 ~9%). 외부 cap을 2187로 키우면 2187×1458 ≈ 3.2M 큐브. → 외부맵 cap 상향이 내부맵 수를 곱으로 늘려 고정 12M을 빠르게 잠식. 셀=내부맵 패턴 자체가 heap 비효율(셀당 1458 과할당).
  • 그래서 grow는 free-list 회수가 필수(선택 아님): grow 시 옛 블록을 반드시 회수해야 12M 안에서 순증식 가능.
FREE(229)는 최상단-복원만 지원(free-list/워터마크 없음 — 소스 확인). → free-list 신규 구현이 W6의 핵심 난도.
  • 대안 트랙(병행 검토): ①MEM_HARD_LIMIT 상향(예 24M, calloc 두 배 = ~648MB RSS, 별도 메모리/회귀 영향) — 가장 단순하나 전 서비스 RSS 증가.
②셀=내부맵 패턴을 flat 슬롯 셀로 바꿔 내부맵 제거(셀코어 변경, 도메인 영향 큼).
  • GC 압력: free_strings 힙스캔이 heap_ptr..MEM_MAX 2패스 → 큰 맵이 heap_ptr를 끌어내려 스캔범위 확대. 워터마크 캐싱으로 완화(여전히 유효).
  • 가드 일반화: 5870 heap_ptr-1458<mem_countheap_ptr - cap*2 < mem_count로. grow 경로에도 동일 가드.
  • 상한 정책: cap 최대 3⁹은 12M 고정 아레나에선 비현실(13122슬롯×다수=고갈). 실효 상한은 heap 잔량 기반 동적으로 재산정 필요.

3. 트윈 아키텍처

[라이브 — 무변경]                      [트윈/섀도 — 신규]
crownyc (현 바이너리)                  crownyc-next (별도 경로, 동적맵)
 ├ /tmp/*.toau (그대로)         dual-run  ├ /Users/ef/CrownyOS/crownyc/build/crownyc-next
 └ /Users/ef/crowny-*/data/*.dat ──복사──→ └ /tmp/twin-{svc}/data/*.dat (복사본, 공유 아님)
       :라이브포트                              :섀도포트 (라이브 + 10000 오프셋)

  • 별도 바이너리 경로: /Users/ef/CrownyOS/crownyc/build/crownyc-next (라이브 crownyc 절대 안 건드림).
  • 섀도 포트: 라이브포트 + 10000 (예: finance 9750 → 트윈 19750). gateway.yaml에 등록 안 함 (SSOT 오염 방지),
로컬 직통 테스트만. 포트 충돌은 crowny-ports.sh check 19750로 사전 확인.
  • 상태 .dat 복사 (공유 금지): 라이브 .dat를 트윈 디렉토리로 복사. 라이브 WAL에 트윈이 쓰지 않게 격리.
on-disk 포맷은 VM-무관 (라인기반 pipe/JSON) → 무변환 로드 검증됨.
  • 후보 서비스 선정:
  • exemplar = finance (9750): 이미 12-파티션으로 729 우회 중 → new VM에서 단일맵 재통합이 가능한지가 최강 검증.
  • 초대DB .dat 로드 후 전 키 맵꺼내 결과를 라이브와 diff. 729 미만 구간 완전일치 기대.
  • 위험高 클러스터 순: finance → church → gateway → enterprise → aimed.
  • dual-run 패리티 검증: 동일 입력 요청을 라이브:9750 + 트윈:19750에 던져 응답 diff.
  • 729 미만 구간: 완전일치 必 (불일치 = 후방호환 깨짐, 즉시 중단).
  • 729 초과 구간: 라이브=silent drop(키유실) vs 트윈=보존 → 신규 동작으로 명시 (후방호환 위반 아님, 손실복구).

  • 4. 단계별 컷오버 게이트

    게이트작업통과 기준
    G0 빌드crownyc-next 컴파일 (cc -O2 -o build/crownyc-next crownyc.c)무경고 빌드 + 기존 회귀 테스트 통과 + cap=0인자(기본) 맵 동작 = 구버전 비트동일
    G1 트윈검증finance .dat 복사 → 트윈 로드 → 전 키 맵꺼내 diff + 삽입순서 재현 패리티729 미만 구간 100% 일치. ★open-addressing 레이아웃은 삽입이력 의존(GC compaction이 재정렬)이므로 단순 키 readback diff 불충분 → 동일 삽입순서 replay 후 맵키목록 순서·맵꺼내 동치 검증. heap_ptr 최저치·free_strings 스캔큐브수 회귀 없음
    G2 카나리 (1서비스)finance 단일 서비스만 crownyc-next로 라이브 전환 (게이트웨이 조율)24h 무장애. 신규 초대 silent drop 0건. 응답 패리티 유지. 롤백 미발동
    G3 클러스터Finance 클러스터 순차 (bank→auth→dex→wallet→chain). 연동그래프 순서 준수클러스터 내부 호출 체인 정상. 상태 정합 (WAL replay 순서 보존)
    G4 전함대위험高 잔여(church/gateway/enterprise/aimed) → 나머지 28서비스33서비스 전체 crownyc-next. 7일 안정화. 12M heap 한도 여유 확인
    클러스터 기동 순서 (연동그래프 근거): ①Infrastructure → ②Finance → ③Development → ④Business/Community/Entertainment. gateway는 reverse proxy 허브라 마지막에 가깝게 (블라스트 반경 최대). Terminal/code는 다중 클러스터 게이트웨이.


    5. 롤백

    • 백업: 컷오버 직전 cp crownyc crownyc.$(date +%s).bak (구 바이너리 보존, 롤백 원본).
    • 원자 스왑: mv build/crownyc-next crownyc (cp 덮어쓰기 금지 — 실행중 바이너리 cp는 손상. mv = 원자 rename).
    • 즉시 복귀: mv crownyc.{ts}.bak crownyc + 대상 서비스 재시작. 게이트웨이는 SIGHUP rolling restart.
    • 롤백 트리거 (자동 발동 기준):
    1. 729 미만 구간 패리티 불일치 (후방호환 깨짐) → 즉시. 2. heap 부족 stderr ([MAP] 힙 부족) 또는 OOM → 즉시. 3. 카나리 24h 내 장애 1건 이상 → 게이트 미통과, 롤백. 4. WAL replay 정합 실패 (상태 손상) → 즉시 (.dat 복사본이라 라이브 원본은 안전).

    ★롤백 경계 (point-of-no-return) — 적대검증 정정★: 롤백이 비트-클린한 것은 모든 맵이 ≤729(구 실효 cap)인 동안만이다. new-VM이 730번째 키를 받는 순간(=근본해결이 실제 발동) 그 상태는 구 VM으로 표현 불가 → 그 시점 이후 구 바이너리로 롤백하면 >729 엔트리 유실. 즉 카나리 통과 후 실데이터가 729를 넘기 시작하면 그 맵은 사실상 비가역. 운영 정책: ①카나리 기간은 인위적으로 729 미만 유지하며 후방호환만 검증, ②"근본해결 발동(>729 허용)"은 별도 명시 게이트로 되돌릴 수 없음을 선언하고 진입. .dat 복사본은 라이브 원본을 지키지만, 컷오버된 라이브가 >729를 쓰면 그 라이브 상태 자체가 구 VM 비호환이 됨.

    6. 위험 레지스터

    #위험블라스트반경완화
    R1후방호환 깨짐 (cap=729 폴백 시 해시분포 변화 → 기존 .dat 키 미스)전 서비스cap=729일 때 trit_hash 분포 비트동일 강제. G0에서 구버전 비트동일 검증. G1 diff 100% 일치 게이트
    R2상태 정합 (WAL replay 순서/메타카운터 불일치)finance/chain/bank/reward.dat 복사(공유 금지)로 라이브 원본 격리. meta 카운터(count\partition) 매칭 검증. replay 순서 보존
    R3heap 고갈 (동적맵 누적 + GC 스캔범위 확대)메신저/웹 등 문자열多 서버mem_ensure realloc 연동. cap 상한 3⁹. free-list 단편회수. GC 워터마크 캐싱. G1에서 heap_ptr 계측
    R4블라스트 반경 (gateway=reverse proxy 허브, 전 트래픽 경유)전 함대gateway는 G4 후반. 카나리=finance(독립성 높음). 섀도포트로 라이브 무영향 검증 선행
    R5세션 조율 (라이브 프로세스/게이트웨이 스왑은 본 세션 영역 밖)계획·트윈·패리티까지만 본 세션. 라이브 바이너리 스왑·재시작은 인프라/게이트웨이 세션 사인오프 필수
    R6맵키목록 2차 truncation (>1023키는 프로빙과 독립적으로 잘림)큰 맵 보유 서비스op852 결과배열 1024→cap+1 동적화. cap 인지 스캔. 이건 grow와 별개 수술 사이트
    R7단편화 누적 (grow 옛블록 회수 불가 시 heap 잠식)장기 운영free-list 등록. FREE(229) 최상단-복원 시맨틱과 정합. 장기 누적 모니터링

    7. 타당성 Verdict (정직)

    소화 가능 (Opus+울트라 범위):

    • VM 수술 자체 (8개 사이트: op412/413/414/852 + trit_hash + heap_ptr/ALLOC/FREE + GC + MEM가드). 국소적·잘 정의됨.
    • 후방호환 additive 설계 (cap 메타슬롯 + 0인자 폴백). 데이터 레이아웃 불변이라 디스패치 arity 무변경.
    • 트윈 빌드·섀도포트·dual-run 패리티 하니스. 전부 읽기/측정/별도경로 — 라이브 무영향.
    • G0~G1 (빌드+트윈검증)은 본 세션 단독 완수 가능.
    도메인/인프라 세션 사인오프 필수 (정직):
    • G2~G4 라이브 컷오버: 실행중 공유 crownyc 바이너리 스왑 + 33서비스 재시작 = 인프라/게이트웨이 세션 영역 (R5).
    본 세션은 계획·트윈·패리티 데이터까지만 책임. 라이브 mv 스왑은 조율 권고.
    • gateway 재구성: SIGHUP rolling restart, trident/health 캐시 복구는 gateway 세션 담당.
    • 각 도메인 서비스 검증: finance/church/enterprise의 비즈니스 로직 정합은 해당 도메인 세션이 확인.
    결론: VM 근본해결 설계+트윈 구축은 GO (Opus 단독 소화). 라이브 함대 컷오버는 조율 GO (게이트별 세션 사인오프). 한선씨 헌법 정합 — VM은 C 수술이나 동일 로직 .한선 동반/패턴학습 대상 (셀코어 룰 변환 가능).


    8. 작업 분해 (WBS) — 다음 실행 단위

    ID작업의존세션
    W1crownyc.c 복사 → 수술용 트리 (build/ 격리). 라이브 무변경
    W2op412 맵생성: 선택적 cap 인자 + 메타슬롯(va+1) + cap2 할당 + 가드 일반화W1
    W3op413/414 맵넣어/맵꺼내: 729→cap 메타읽기 치환 + 부하율 rehash-growW2
    W4op852 맵키목록: 결과배열 1024→cap+1 동적화 + cap 스캔W2
    W5trit_hash cap-투영 (cap=729 비트동일 보존, cap>729 k트릿 확장)W2
    W6heap: mem_ensure grow 연동 + free-list 단편회수 + GC 워터마크 + cap 상한 3⁹W3
    W7G0 빌드 + 회귀: cap=0(기본) 맵 구버전 비트동일 검증 하니스W2~W6
    W8동일 로직 .한선 동반 (맵grow 셀코어 룰) + 패턴 학습 등록W7
    W9트윈 하니스: finance .dat 복사 → 섀도포트 dual-run → diff 도구 (한선씨)W7
    W10G1 패리티 검증 + heap_ptr/GC 계측 리포트W9
    W11G2 카나리 컷오버 (finance) — 라이브 mv 스왑W10인프라/게이트웨이 조율
    W12G3 클러스터 (Finance 순차)W11인프라 조율
    W13G4 전함대 + gateway 마지막W12게이트웨이 세션
    다음 즉시 실행: W1 → W2 (맵생성 cap 헤더 수술이 모든 후속의 기반).


    9. 실행 로그 — W1·W2·G0 완료 (2026-06-11)

  • W1 격리: crownyc.cbuild/crownyc-next.c 복사. 라이브 crownyc/crownyc.c 무접촉(확인: 라이브 바이너리 size/mtime 불변, finance 라이브 health ok).
  • W2 cap-헤더 수술 (4 사이트만): 맵을 cap-인지로. 핸들 va에 cap 헤더, 엔트리 base=va-1.
  • op412 맵생성: 기본 cap=729, mslots=cap*2+1, 헤더에 cap 기록.
  • op413 맵넣어 / op414 맵꺼내: 729→헤더 cap 읽기, base=va-1 프로빙.
  • op852 맵키목록: 729→cap 스캔, base=va-1.
  • 가비지 가드 mcap<1||>MEM_MAX→729. cap=729일 때 %729·관측동작 불변(0인자=후방호환).
  • 빌드: cc -O2 -I.. -o build/crownyc-next build/crownyc-next.c -lm -lpthread -framework Security -framework CoreFoundation (라이브 링크와 동일, 확인). exit 0.
  • G0 회귀 — cap=729 비트동일 (라이브 vs next diff):
  • 맵 토처(오버라이트/200엔트리/int·str키/missing/keylist): ✅ 동일 (합=139300).
  • 중첩맵(map-of-maps, 셀코어 새셀 패턴, 50셀): ✅ 동일 (중첩합=3675). finance 초대DB 위험 패턴 검증.
  • 변경 표면=맵 4 opcode뿐, 나머지 VM은 라이브와 byte-동일 → 비-맵 회귀 불가.
  • 상태: G0 통과. 산출물 build/crownyc-next(격리), 라이브 무영향.
  • 다음 — W3 (난도 핵심)

    rehash-grow(부하율>cap2/3 → cap3 재해시) + free-list 단편회수(고정 12M 아레나, FREE는 top-of-heap만 → 신규 구현 필요). 이게 근본해결의 실난도. 그 후 W4(keylist>1023)·W5(hash cap-투영)·W6(heap)·G1(finance .dat 트윈 패리티, 삽입순서 replay).

    10. W3 완료 — rehash-grow + forwarding + free-list (2026-06-11, 격리)

    울트라 워크플로우(설계2→구현→적대검증3). build/crownyc-next.c 단독, 라이브 무접촉.

    • 블록 레이아웃: slots=cap*2+2 (헤더 va=cap + 엔트리 2cap + count 메타 va-2cap-1). 부하율 O(1).
    • rehash-grow: 신규삽입 후 3*newcount>2*mcap(>2/3) → cap'=cap*3(729→2187→6561…) 새 블록 재해시. cap=729·≤486 구간은 G0과 100% 동일(grow 미발동).
    • ★forwarding(중첩맵 핸들 안정) — 핵심★: grow가 블록 재배치 → 옛 핸들 stale. forwarding 마커로 옛→새 리다이렉트. 적대검증이 in-block 마커가 free-list 재사용과 충돌함을 발견 → forwarding 사이드테이블(fwd_old/fwd_new 65536슬롯 + 툼스톤)로 블록 메모리와 분리. map_resolve(va)가 모든 맵 op 진입부에서 체인 follow(guard 64).
    • free-list: cap-클래스(7293^k)별 LIFO. 적대검증이 "DEAD on arrival"(미배선) 적발 → 수리(map_grow가 옛 블록 등록 + 재사용 시 stale 사이드테이블 툼스톤). same-cap 처닝은 회수, grow-discard는 map-GC 부재로 완전bound 아님(grow 기하적이라 폐기 적음 — 향후 정제).

    검증 (독립 재확인)

    • 빌드 exit 0(608768B). G0 cap=729 비트동일 유지.
    • 중첩-grow crux: 외부맵에 내부맵 저장→내부맵 1500키 grow(재배치)→외부 경유 옛핸들 조회 k1=1,k1500=1500,합=1,125,750(정확). 라이브는 729서 유실(합=265314). forwarding 자가치유 입증.
    • T1 단일2500키 0유실 / T3 공유alias 양방향 / T4 경계(486/487/729/730/1457/2187/2188) / finance .dat 부팅·로드 무손상.
    • 라이브 crownyc(608520,01:18)·crownyc.c·:9750 무접촉.

    잔여(정직)

    • map-GC 부재 → grow-discard 누적 완전bound 아님(grow 기하적이라 실용 OK, 향후 map-GC 정제).
    • 다음: G1(finance .dat 트윈 패리티, 삽입순서 replay) → G2~ 라이브 컷오버(인프라/게이트웨이 사인오프 + 롤백 경계 수용).

    11. G1 완료 — finance 트윈 A/B 패리티 (2026-06-11, 라이브 무접촉)

    격리 트윈: 라이브 소스 sed(포트 9750→19750, data→/tmp/twin-finance/data), hanseonc_high 컴파일(VM-무관 toau), 같은 toau를 라이브 crownyc vs build/crownyc-next에 각각 fresh .dat 복사로 기동·동일요청·diff. 라이브 crownyc/finance/data 무접촉 확인.

    결과

    1. ✅ 729-미만 패리티 = 완전 비트동일: 실제 finance 상태(162 연락처=중첩 map-of-maps) 기준 boot replay·sync·join·rewards·feed·stats·shareholder·멱등rejoin 18줄/2244바이트 동일. 729 미만 구간에서 crownyc-next는 완벽한 drop-in.
    2. ✅ 캡 초과 = 결정적·완전 (정밀 재측정): 빈 상태 1000 고유연락처 + 재시도/페이싱 하니스next: registered 1000/1000, retrievable 1000/1000, 손실 0 vs live: retrievable 242, 손실 758. crownyc-next는 finance 1000 연락처에서 무손실.
    3. ⚠️→정정: "2차 한계"는 측정 아티팩트였음: 초안의 817/880·"finance 2차 한계"는 단일스레드 raw 한선씨 백엔드에 1000요청 rapid-fire 시 HTTP 전송 드롭이 손실로 오집계된 것. 재시도+페이싱 하니스로 재측정하니 next 1000/1000 완전. → 측정 파이프라인을 먼저 의심하라([[feedback_test_matrix_traps]]). finance 자체엔 (이 스케일에선) VM 캡 외 추가 손실 한계 없음.

    컷오버 함의 (정직)

    • G2 카나리는 729-미만에서 후방호환 검증(perfect parity 입증). 롤백 경계와 정합.
    • ">729 근본해결 발동"은 VM 수술만으로 finance 1000 연락처 무손실 입증됨(2차 감사 불요). 단 더 큰 스케일(수천+)의 heap/map-GC 한계는 미측정(디스크 100% ENOSPC로 3000 테스트 중단) — 향후 디스크 확보 후 ceiling 측정.
    • map-GC(W3 잔여) [MAP] 힙 부족 미발생(1000 무크래시) — 당장 차단요인 아님.

    상태

    G0·W3·G1 = 본 세션 단독 완료(격리, 라이브 무접촉, finance 1000 무손실 입증). 다음: ①디스크 확보 후 finance ceiling(수천 연락처) 측정, ②G2~ 라이브 컷오버(인프라/게이트웨이 사인오프).