
    j&                     Z   d Z ddlZddlZddlmZmZ ddlmZmZm	Z	m
Z
mZmZ ddlmZ ddlmZ ddlmZmZ ddlmZ dd	lmZ dd
lmZ ddlmZmZ  ej<                  e      Z dZ!dZ"dZ#dZ$dZ%dZ&dZ'dZ(dedee)   fdZ*dee+ef   de	ee+ef      fdZ,dee+ef   de-fdZ. G d dee      Z/y)u]   scene_consistency StepRunner — 씬 내 교차 샷 시각적 일관성 고정 요소 추출.    N)ThreadPoolExecutoras_completed)AnyDictListOptionalSetTuple)AppError)
StepRunner)#_normalize_scene_consistency_resultassert_fresh_llm_evidence)_DetailStepMixin)call_structured)sanitize_for_safety)load_promptload_schemaokskipped_single_shotskipped_no_selectionblocked_no_selectionfailed_all_tiersvalidator_violationscontract_violation   rawreturnc                     t               }| |S t        | t        t        f      st	        | d      s|S | D ]  }	 |j                  t        |              |S # t        t        f$ r Y 3w xY w)u  G2.2 helper: applies_to_shots → int set (LLM 변형 출력 강건 처리).

    iter#1 review fix (Codex MINOR): scalar / non-iterable / str 입력 안전 default
    빈 set. str 은 iterable 이지만 char-by-char iter 가 의미 없음 → 명시적 거부.
    __iter__)	set
isinstancestrbyteshasattraddint	TypeError
ValueError)r   outvs      [/Users/manta/Documents/Projects/TheRoad-I1/backend/app/core/steps/scene_consistency_step.py_normalize_applies_to_shotsr,   3   so     EC
{
#U|$GC,D
	GGCFO 
 J :& 		s   AA)(A)scene_resultc                 h   | j                  dg       xs g }|sg S i }|D ]o  }t        |t              s|j                  d      dk7  r)|j                  d      xs dj                         }|sO|j	                  |g       j                  |       q g }|j                         D ]  \  }}t        |      dk  rt        t        |            D ]  }t        |dz   t        |            D ]  }||   ||   }
}	t        |	j                  dg             }t        |
j                  dg             }||z  }|sK|	d	   }|
d	   }|d
vs|d
vrt        dd|d|d|      ||k(  ryt        |      D ]<  }|j                  |||	j                  dd      |
j                  dd      g||gd       >    |S )ud  G2.2 (Area #4 v7): element_scope enum 직접 비교 — close/full overlap 위반 검출.

    같은 character_name 의 character_state element 쌍 중 ``applies_to_shots`` 가
    겹치고 ``element_scope`` enum 값이 다른 위반 검출. v6 의 code-side regex/keyword
    inference 는 폐기됐고, producer (v7 prompt + schema) 가 emit 한 enum 신뢰 (Gate 3).

    fail-fast (Gate 4):
    - ``element_scope`` 누락 → ``KeyError`` (schema violation, call_structured retry 유도)
    - enum 외 값 → ``AppError(step.contract_violation.scene_consistency.element_scope)``

    Returns: violation list. 각 항목은 충돌이 발견된 (shot_index, character_name,
    element_id 쌍, framings 쌍) 정보. 발견 0 = clean.

    Metadata key 의 ``"framings"`` 는 legacy 호환 유지 — 값만 element_scope enum
    (``"full"`` | ``"close"``).
    fixed_elementselement_typecharacter_statecharacter_name       applies_to_shotselement_scope)fullclosez7step.contract_violation.scene_consistency.element_scopez.scene_consistency: invalid element_scope pair /z for )codemessage
element_id)
shot_indexr2   elementsframings)getr!   dictstrip
setdefaultappenditemslenranger,   r   sorted)r-   fixedby_charfename
violationsr?   ije1e2shots1shots2overlaps1s2shot_idxs                    r+   _detect_framing_conflictsrY   G   s   " -r28bE	 02G"d#66.!%66'(.B5574$++B/  (*J!--/hx=1s8}%A1q5#h-0!!hqkB4RVV<NPR5ST4RVV<NPR5ST 6/ ((.."<M2M"VL!fAbV5:  8 &wH%%&.*.FF<4FF<4% &(H
' 
 !0- 1 & *L     c                 x    | j                  d      xs d}|t        t        t        t        fv ryt        |       ryy)ur  G2.1+G2.2 consumer-side defense single-source helper (iter#4 review fix).

    consumer (scene_context_loader, shot_dependency_t2i_step) 가 ``fixed_elements``
    를 LLM prompt 에 주입하기 전에 호출. ``False`` 면 skip + warning.

    2-tier 검사:
    1) status 직접 차단 — failed_all_tiers / blocked_no_selection / validator_violations.
    2) status='ok' 또는 status=None 옛 cp — ``_detect_framing_conflicts`` 직접 호출
       (downstream-only force-run 시 dispatcher gate 통과 path 보호).

    consumer 마다 같은 가드 로직 복제 → drift 위험. 본 helper 가 single source.
    statusr3   FT)rA   STATUS_FAILED_ALL_TIERSSTATUS_BLOCKED_NO_SELECTIONSTATUS_VALIDATOR_VIOLATIONSSTATUS_CONTRACT_VIOLATIONrY   )r-   r\   s     r+   is_scene_result_consumer_safera      sE     x(.BF##!	   .rZ   c                       e Zd ZdZddeeef   fdZd Z	 dde	de
e   ded	ed
edee	ee	ef   f   deeef   deeef   deeef   dee
eeef         deeef   fdZy)SceneConsistencyStepuR   씬 내 2+ 샷에 걸친 고정 시각 요소 추출 (scene_detail 직전 실행).r   c                 n  B | j                  d      }|r"|j                  di       j                  dg       ng }| j                  d      }| j                  d      }|r|st        ddd	      |j                  di       j                  d
      st        ddd	      |j                  di       j                  d
      st        ddd	      | j                  d      }| j                  d      }| j                  d      }| j                  d      }	i }
|rO|j                  di       j                  d
      r.|d   d
   D ]#  }t        |j                  dg             |
|d   <   % i }t               }|r|j                  di       j                  d
      r|d   d
   D ]}  }|d   }|
j                  |      }|-t        j                  d|       |j                  |       g ||<   H|j                  dg       D cg c]  }|j                  d      |v r| c}||<    i }|rx|j                  di       j                  d
      rW|d   d
   D ]L  }|j                  d      }|j                  dg       D ci c]  }|j                  d      s|d   | c}||<   N i }|rX|j                  di       j                  d      r7|d   d   D ],  }|j                  d       d|j                  d       }|||<   . i }|rd|j                  di       j                  d
      rC|d   d
   D ]8  }|d   }|j                  dg       D ]  }|j                  dg       |||d   f<    : i }|	r\|	j                  d      rKdD ]F  }|	d   j                  |g       D ],  }|j                  dd      }|s|j                  dd      ||<   . H i }|D ]  }|||j                  dd      <    t        dd       }t        dd!      }| j                  d"      }|r|j                  d      rp|d   } g }!| j                  d#      r|!j                  d$| d#           | j                  d%      r|!j                  d&| d%           |!r|d'd(j                  |!      z   z  }t        t        t        t        f}"| j                  d      }#i }$|d)k(  r|#r|#j                  di       j                  d
      r|#d   d
   D ]i  }|j                  d      }|j                  d*      }%|%|"v r*|%9|j                  d+d      xs d}&|&j                  d,      s|&j                  d-      re||$|<   k |$rt        j!                  d.t#        |$             g }'d}(d})d}*d}+g },t%        |j'                               D ]  \  }}-||v r |'j                  |d/g t        d0       |+d1z  }+*t#        |-      dk(  r |'j                  |d2g t(        d0       |)d1z  })Xt#        |-      d3k  r |'j                  |d4g t*        d0       |)d1z  })||$v r*t-        |$|   d56       |'j                  |$|          |(d1z  }(|,j                  ||-f        |,rt/        t0        j2                  j                  d7d8            }.t5        d1t7        |.t#        |,                  }.t        j!                  d9t#        |,      |.|(|)       t9        |.:      5 }/|,D -ci c]J  \  }}-|/j;                  | j<                  ||-|j                  |i       j                  d;d      ||||||
      |L }0}}-t?        |0      D ]3  }1|1jA                         \  }2}3|'j                  |2       |3r|*d1z  }*/|(d1z  }(5 	 d d d        |'jC                  d< =       d}4|'D ]  }5|5j                  d*      }6|6d tD        fvr|69|5j                  d+d      xs d}&|&j                  d,      s|&j                  d-      rZtG        |5      }7|7sh|7|5d><   t        |5d*<   |4d1z  }4t        j                  d?|5j                  d      t#        |7              |,D 89ch c]  \  }8}9|8	 }:}8}9tI        |'      D ]  \  };}5|5j                  d*      t        k7  s|5d   |:vr&|5d   }| j=                  ||j                  |g       |j                  |i       j                  d;d      |||||||5d>   @
      \  }<}=|=stG        |<      r t        |5d*<   t        j                  dA|       |<|'|;<   |4d1z  }4t        j!                  dB|        d}>|'D ]  }5|5j                  d*      }6|6d tD        fvr|69|5j                  d+d      xs d}&|&j                  d,      s|&j                  d-      rZg }?|5j                  dCg       xs g D ]9  BtK        BfdDdED              sBj                  dF      dGk(  r-	 tM        Bd       ; |?s|?|5dK<   t        |5d*<   |>d1z  }>t        j                  dL|5j                  d      t#        |?              |(|)z   |*z   |+z   }A|(|)z   |4z
  |>z
  |A|*|+z   tR        |+|4|>d
|'idMS c c}w c c}w c c}-}w # 1 sw Y   xY wc c}9}8w # t        $ rH}@@jN                  dHk7  r |?j                  Bj                  dI      @jP                  dJ       Y d }@~@d }@~@ww xY w)NN
scene_savedatasegmentsshot_validatorshot_selectionzstep.no_inputu0   shot_extract 또는 shot_selection 결과 없음i  )r;   r<   status_codescenesu(   shot_extract data.scenes가 비어있음u*   shot_selection data.scenes가 비어있음beat_extractshot_stagingshot_directorentity_mergeselected_shot_indicesscene_indexuC   scene_consistency: scene %d missing from shot_selection — blockedshotsr>   beats
beat_index_visible_entity_ids)
characters	locationspropsshort_idr3   rM   r   scene_consistencysystemschemavisual_world_ruleserau   시대: regionu   지역/국가: u?   

## 세계관 맥락 (인물 묘사 시 인종/국적 참고)

resumer\   analysis_summary   분석 실패   분석 차단z:scene_consistency resume: %d scenes already done, skippingu'   분석 차단 — shot_selection 누락rq   r   r/   r\   r5   u8   스킵 — selected_shot_indices=[] (명시적 deselect)r4   u0   단일 샷 — 교차 일관성 분석 불필요z#scene_consistency.existing_ok_reusewhereSCENE_CONSISTENCY_WORKERS5z[scene_consistency: %d scenes need LLM (workers=%d, already_done=%d, single_shot_skipped=%d))max_workerstextc                 &    | j                  dd      S )Nrq   r   )rA   )rs    r+   <lambda>z/SceneConsistencyStep._execute.<locals>.<lambda>  s    }a)@rZ   )keyr   z6scene_consistency S%s: %d framing conflict(s) detected)correctionsuI   scene_consistency S%s: 충돌을 알려 주고 다시 물어도 남았다uC   scene_consistency S%s: 충돌을 알려 주고 다시 물어 해소r/   c              3   &   K   | ]  }|v  
 y wN ).0felements     r+   	<genexpr>z0SceneConsistencyStep._execute.<locals>.<genexpr>  s       2A1< 2s   )source_factsvisual_inferencescreative_decisions
confidencer   legacyzstep.contract_violationr=   )r=   errorcontract_violationsz8scene_consistency S%s: %d contract violation(s) detected)completed_countapplicable_countfailed_countschema_versionblocked_countvalidator_violation_countcontract_violation_countrf   )*_load_prev_checkpointrA   r   r    loggerwarningr%   r   r   rE   joinr]   r^   r_   r`   
startswithinforG   rI   rF   STATUS_SKIPPED_NO_SELECTIONSTATUS_SKIPPED_SINGLE_SHOTr   r&   osenvironmaxminr   submit_process_one_scener   resultsort	STATUS_OKrY   	enumerateanyr   r;   r<    SCENE_CONSISTENCY_SCHEMA_VERSION)Cselfmodescene_save_cprg   shot_extract_cpshot_selection_cpbeat_extract_cp
staging_cpshot_director_cpentity_merge_cpselected_mapscshots_by_sceneblocked_no_selection_scenessiselshbeats_by_scenebstaging_mapstr   shot_director_veentity_namesetypeesidseg_by_scenesegsystem_promptr}   rules_cprdworld_lines_retry_statusesexisting_cpexisting_ok	sc_statussummaryscene_results	processedskippedfailedblockedtasksrr   _max_workerspoolfuturesr   r   	is_failedr   r   r_statusrN   t_siru   	asked_nowidxretriedretry_failedr   contract_errorsexctotalr   sC                                                                     @r+   _executezSceneConsistencyStep._execute   s   22<@HU=$$VR044ZD[]445EF 667GH&7$J 
 ""62.228<$B 
 !$$VR044X>$D 
 44^D//?
55oF44^D (*!2!6!6vr!B!F!Fx!P'/925bff=TVX6Y2ZR./ : 13 14#2262>BB8L%f-h7&"&&r*; NN] 033B7)+N2& &(VVGR%8*%8r66,/36 %8*N2& 8( 682262>BB8L%f-h7VVM*02w0C&0C1quu\GZAlOQ&0C&r" 8 (**..488A (1./q1E0FG#%C  2
 /1 0 4 4VR @ D DX N&v.x8&&&"-B?AvvFZ\^?_$b"\*:%;< . 9 (*226:=(044UB?A%%
B/C,-EE&",=S) @ > )+C69L23  $$7B0(; --.BCV,&!BKvve}""Xbi[#9:vvh""_R\N#CD99[12 $''%	
 001DE')80K0O0OPX0Y!&)(3VVM*FF8,	/$ !ff%7<BG))/:g>P>PQ`>a "$B 4 XZ]^iZjk %'	 /1 4 4 67IB 00$$#%(Q&(9	&  1
 5zQ$$#%(b&(9	&  15zA~$$#%(Z&(8	&  1[  4O? $$[_5Q	LL"e%a 8f rzz~~.I3OPLq#lCJ"?@LKKmE
L)W $= &+
 &+	E KK//E$((R044VR@%v&(8$k  &+  
 &g.A()
%FI!((0 !!Q	 / >( 	@A %&!AuuXHi0055!3R8>B%%o6':L:L_:]215J,6()9()Q.)LEE-(#j/ 0 *//gdAT	/.FCuuX"===AQYbAb=!B$($;$;N&&r2.  R(,,VR8v 0k45 %< %!G\ 8A9(jlno!(M#%*%KK]_ab% /2 $% AuuXHi0055!3R8>B%%o6':L:L_:]46O55!126<"<
   2    ;;|,8-g7JK =. +:'(7((A-(NEE-(#o*>K T G#f,w6 !*G 37PPSkk %"W, ?$)B(@}-
 	
A	*&n
 >=h 0j   xx#<<#**&-kk,&?!$,  sP   5i .iiiAi
%Ai:ii#
ii#	j4,=j//j4c                 4   ddl m} t        | dd      }|&| j                  d      }|s |ddgddg g d	
      S |}|j	                  di       j	                  dg       xs g }|D ]  }t        |d        g }g }g }g }	|D ]  }|j	                  d      }
|j	                  d      }|t        k(  r|j                  |
       A|t        k(  r|j                  |
       \|t        k(  r|j                  |
       w|t        k(  r|	j                  |
       |\|j	                  dd      xs d}|j                  d      r|j                  |
       |j                  d      r|j                  |
       |dt        fv st        |      s|j                  |
        t        |      }t        |      t        |      z   t        |      z   t        |	      z   }|rg }|r%|j                  t        |       d| d|dd         |r%|j                  t        |       d| d|dd         |r%|j                  t        |       d| d|dd         |	r%|j                  t        |	       d| d|	dd          |d|d|||||	d
      S  |dg d|g g g g d
      S )u  Group 1 #3 + Group 2 #1 (visual_pipeline_contracts_plan): 산출물 검증.

        scene 별 ``status`` 필드 (G2.1) 우선:
        - ``failed_all_tiers`` → partial (3-tier 모두 실패)
        - ``blocked_no_selection`` → partial (shot_selection 누락 silent skip 차단)
        - ``validator_violations`` → partial (G2.2 framing × fixed_element 충돌)
        - ``skipped_single_shot`` / ``skipped_no_selection`` / ``ok`` → clean

        backward-compat: status 없는 옛 cp 는 ``analysis_summary`` prefix 로 fallback —
        "분석 실패" → failed, "분석 차단" → blocked. (G1.3 startswith 정렬 유지.)

        source 우선순위: step_runner 가 보존한 ``_last_execute_result`` (Codex review
        Critical: exit verify 가 save_checkpoint 전 호출 → fresh run 에서 cp 부재) →
        cp ``_load_prev_checkpoint`` fallback. 둘 다 없으면 missing.

        fail-fast 정책 — 빈 결과 (``fixed_elements: []``) silent 통과 차단.
        r   )CompletionReport_last_execute_resultNr{   Fu+   scene_consistency cp + result 모두 부재missing)total_scenesfailed_scenesblocked_scenes)is_completer   severitymetadatarf   rk   z#scene_consistency.verify_completionr   rq   r\   r   r3   r   r   r:   z scene(s) all-tier failed:    u+    scene(s) blocked (shot_selection 누락): z- scene(s) framing conflict (G2.2 validator): z. scene(s) evidence contract violation (G3.1): partial)r   r   r   violation_scenescontract_scenesTclean)app.core.integrity_reportr   getattrr   rA   r   r]   rE   r^   r_   r`   r   r   rY   rG   )r   r   r   cpr   r   r   r   r   r   r   r\   r   r   issues_countmissing_liness                   r+   verify_completionz&SceneConsistencyStep.verify_completion  sH   $ 	? 5t<>++,?@B' %JK&())+*,		 	 F

62.228R@FB A/> 
 $&$&&(%'A}%BUU8_F00$$R(44%%b)44 ''+22&&r*~55!3R8>B%%o6!((,%%o6"))"- $	**,Q/$++B/E H M"^!44"#$&)/&:; 	 ')M$$=)*!E72M$Ra()+ $$>*+1UG 400>r0B/CE  $$+,-Qug 6))9"1)=(>@ $$?+,AeW 5))8!)<(=? $!%"$)%2&4(8'6	   b7 %!#"$$&#%	
 		
rZ   Nr   rr   
scene_textr   r}   r   r   r   r   r   c                 $   d}|
r!|ddj                  d |
D              z   dz   z  }|d| dz  }|d| dz  }|d	t        |       d
z  }|D ]  }|j                  dd      }|d| dz  }|d|j                  dd       dz  }|j                  d      }|re|j                  |i       j                  |      }|rB|d| d|j                  dd       d|j                  dd       d|j                  dd       d	z  }|j                  ||fg       }|rNg }|D ]/  }|j                  |d      }|j                  |r| d| dn|       1 |ddj                  |       dz  }| d| }|	j                  |      }|s0|j                  dd      }|j                  dd      }|r	|d | dz  }|r	|d!| dz  }|j                  d"g       }|s|D ]~  }|j                  d#d      }|j                  d$d      }|j                  d%d      }|d&   }|j                  d'      xs d}|d(   }d)| |rd*| ndz   } d+| }!|d,| d-| d| |  |! d	z  }  |d.z  }	 t	        d/|||| j
                  d0| |
rd1ndz   | j                  |
rd2gnd3d4|i5      6      }"||"d4<   t        |"d7<   t        j                  d8|t        |"j                  d9g                    |"d:fS # t        $ r.}#t        j                  d;||#       |d<g t        d=d>fcY d3}#~#S d3}#~#ww xY w)?u  한 씬 처리 (Gemini → sanitize fallback → GPT fallback).

        Returns: (result_dict, is_failed).
        result_dict는 scene_results에 바로 append 가능한 형태 (scene_index 포함).
        is_failed는 3-tier 모두 실패한 경우만 True.

        ``corrections`` — 직전 답의 G2.2 위반(`_detect_framing_conflicts` 결과). 있으면
        그 자리만 짚어 다시 묻는다. 규칙은 system 의 「scope 중복 금지」 그대로다.
        r3   u@   [수정 요청] 직전 답이 scope 중복 금지를 어겼다:
c              3      K   | ]r  }d |j                  d       ddj                  d t        |j                  dg       |j                  dg             D              z   d|j                  d       d	z    t y
w)z- r2   z: u    · c              3   2   K   | ]  \  }}| d | d  yw)()Nr   )r   r   r   s      r+   r   zDSceneConsistencyStep._process_one_scene.<locals>.<genexpr>.<genexpr>  s#     h6gda1QCqk6gs   r?   r@   u
    가 Shot r>   u    에 함께 적용됨
N)rA   r   zip)r   r*   s     r+   r   z:SceneConsistencyStep._process_one_scene.<locals>.<genexpr>  s      i %A QUU+,-R0++hc!%%
B:OQRQVQVWaceQf6ghhiquu\233JKL %s   A8A:r   u   씬 u   번 분석

u   씬 텍스트:
z

u   [선택된 샷 목록 — u   개]
r>   r   z

--- Shot z ---
u   설명: descriptionbased_on_beatzBeat #z [change_typez]: before_stateu    → after_stater  r  u   등장 요소: z, ru   camera_directionlighting_moodu   카메라: u   조명: character_angles	characterangle	body_posegaze_direction_kindgaze_target_idsubject_statez, gaze=u   →z, state=u     인물 배치: u    — u  
[지시]
위 샷들을 분석하여, 2개 이상의 샷에 걸쳐 동일해야 할 시각적 요소를 추출하세요.
특히 다음에 주의:
- subject_state가 immobilized인 인물의 자세와 위치
- key_bg_elements/state가 명시한 환경 상태
- shot 간 고정되어야 하는 registered prop/background element 위치
- 샷 사이에 상태가 바뀌는 요소는 제외
- description에 엔티티 ID(C##, L##, P##)를 절대 사용하지 마세요. 보통명사로만 묘사하세요.
r{   scene_consistency__retryretryNrq   )
extra_tagsextra_metadata)stepr   user_promptresponse_schemaproject_configschema_nameopik_metadatar\   z(scene_consistency S%d: %d fixed elementsr/   Fz*scene_consistency S%d all tiers failed: %sr   r   T)r   rG   rA   rE   r   r%  build_opik_metadatar   r   r   	Exceptionr   r]   )$r   r   rr   r  r   r}   r   r   r   r   r   r#  r   sh_idxbeat_idx	beat_datave_listve_namesvidrM   staging_keystagingcamlightchar_anglesa_cn_angle_pose_kind
_target_id_state	_gaze_str
_state_strr   r   s$                                       r+   r   z'SceneConsistencyStep._process_one_scene  s   . ^acahah i %	i b 
  K 	bT00)*T::3CJ<vFFBVVL!,F[77KXbff]B&?%@CCKvvo.H*..r26::8D	 
"Y]]="-M,Nc$==<=U9==Q^`bCcBddfhK
 '**B<<G"C'++C4DOOse1TF!$4#F # 81D0ERHHD&*K!ook2Gkk"4b9OR8[R#88KXeWB#77K%kk*<bA(eeK4!"w!3 !k2 6 !""7 8%&UU+;%<%B
!"?!3&-eW$5z3zl9K_a$b	'/x%8
#):3%uVHBugV_U`ak`lln'oo )C \ 	C		
	$(+' &#2205[VXY"66,7yT$12#6 7 8
F %'F=!(F8KKBBFJJWgikLlHmn5=  	LLEr3O!$3"$1	
  	s   A?K 	L!#L
L
L)r   r   )__name__
__module____qualname____doc__r   r"   r   r   r  r&   r   rB   tuplelistr   r
   boolr   r   rZ   r+   rc   rc      s    \c
c3h c
JH
j 7;uu Dzu 	u
 u u S$sDy/12u ud{+u 38nu #t)_u d4S>23u 
tTz	urZ   rc   )0rA  loggingr   concurrent.futuresr   r   typingr   r   r   r   r	   r
   app.core.errorsr   app.core.step_runnerr    app.core.steps._evidence_helpersr   r   app.core.steps.detail_stepsr   app.modules.llm.llm_clientr   app.modules.llm.safetyr   _sanitize_for_safetyapp.modules.prompt_loaderr   r   	getLoggerr>  r   r   r   r   r^   r]   r_   r`   r   r&   r,   r"   rY   rD  ra   rc   r   rZ   r+   <module>rQ     s    c  	 ? 8 8 $ + 9 6 N >			8	$ 	2 4 4 , 4 0  $%  S SX (IDcN ItDcN?S IXS#X 4 4g	+Z g	rZ   