
    FJj~                       d Z ddlmZ ddlZddlZddlmZmZmZm	Z	m
Z
 ddlmZ ddlmZmZ ddlmZ  ej$                  e      ZdZd	d
ddZddhZdhZdZdZd'dZd(dZd)dZ G d de      Z G d de      Z d*dZ!	 	 	 	 	 	 	 	 d+dZ"dZ#d,dZ$dd	 	 	 	 	 	 	 	 	 d-dZ%dd	 	 	 	 	 	 	 	 	 	 	 	 	 d.dZ&d Z'dZ(d!Z)d"Z*d#Z+d$dddd%	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 d/d&Z,y)0uo  shot_continuity_author — 자세 정본·중의어 교정·carried state 저작 (2026-07-13).

s40/s41 레시피의 텍스트 안전망 3종(스틸·콘티 프롬프트에 주입될 연속성 문장)을
LLM 으로 저작한다. 정본: scratchpad/forest_exp/s37_rooftop_rebuild.py
stage_pose_canon / stage_pose_fix / stage_int_cont.

  1) pose_canon: 움직일 수 없는 인물(사망·의식불명)의 자세 정본 —
     등장 전 샷에 글자 그대로 재사용, 중의어(위치 lie 등) 회피.
  2) carried: 샷별 '이어받는 상태' — ★양방향 전파·씬 경계 차단은
     프롬프트 계약이 담당(코드 재구현 금지). 실험의 실내 한정(int_cont)을
     전 샷으로 일반화(계약 첫 줄만 수정, 규칙 본문 verbatim).
     ★v3(감사 1-B) 부터 **세 갈래**로 받는다 — objects / people[] /
     offscreen_effects. 누가 화면에 보이는지는 모델이 아니라 **코드가
     그 샷의 visible entity id 로** 정한다(`carried_text_for_shot`).
  3) pose_fix: 정본 샷의 movement/figures/state 문장 중의성 최소 교정.
     production v1 은 movement/figures 저작이 없으므로 빈 문자열로 전달
     (state 교정이 실효) — 도입 시 그대로 확장. v3 부터 교정본을
     `carried` 안 **제자리에** 넣는다(종전에는 조립이 두 값을 `or` 로
     골라 **일부러 비운 칸이 옛 값으로 되살아났다**).

코드 강제: pose_canon.shots 의 미지 태그 제거(+경고), carried 전 샷 누락
fail-fast, character_ko → EntityCanon short_id 정확 일치 매핑(불일치=None,
글자 부분매칭 금지).
    )annotationsN)AnyCallableDictListOptional)AppError)load_promptload_schema)tag_ofshot_continuityz1.202607132300z2.202607161500z3.202608270900)123r   r   carried_contract	scoped_v1c           	     n    	 t         |    S # t        $ r  t        d| dt        t                d      w xY w)Nz0unknown shot_continuity prompt version selector z	 (known: ))PROMPT_VERSION_MAPKeyError
ValueErrorsortedselectors    a/Users/manta/Documents/Projects/TheRoad-I1/backend/app/modules/pipeline/shot_continuity_author.pyresolve_prompt_versionr   H   sK    
!(++ 
>l)F+=$>#?qB
 	

s    )4c                    | t         v S )u/   그 팩이 carried 를 세 갈래로 내는가.)_PEOPLE_CONTRACT_PACKSr   s    r   pack_has_people_contractr   R   s    ---    c                v    t        |       xr- t        | xs i j                  t              xs d      t        k(  S )ur  **그 값이** 세 갈래로 저작된 것인가 — 판단 근거는 데이터다.

    ★팩 selector 로 판단하면 안 된다. selector 는 지금 도는 코드의 값이고
     체크포인트는 옛 판에서 만들어졌을 수 있다 — 그 둘이 어긋나면 옛
     한 칸을 새 계약처럼 읽어 **엉뚱한 값을 프롬프트에 싣는다**.
     )boolstrgetCARRIED_CONTRACT_KEYCARRIED_CONTRACT_SCOPED)rows    r   row_has_people_contractr)   W   s8     9 $SYBOO017R8"	#$r    c                  $     e Zd ZdZd fdZ xZS )LegacyCarriedContractu`  옛 한 칸 carried 를 **새 그림을 사는 자리**에서 만났다.

    ★「옛 그림은 이미 나왔다」와 「옛 값이 앞으로 안 쓰인다」는 다르다
     (2026-08-27 Codex 판정). `scene_image` 나 콘티만 force 하면 옛 한
     칸으로 **새 그림을 다시 산다** — 그러면 1-B 가 그대로 재발한다.
     ★**제공자를 부르기 전에** 멈춘다. 소비하는 자리는 샷 하나를
     세우고 나머지를 계속한다 — 스텝을 통째로 죽이면 유일한 구제책이
     `shot_continuity` force 인데 그것은 하류 CP 를 지워 **에피소드의 모든
     이미지를 다시 산다.**

     ★`strict=False` 로 부르는 **프로덕션 경로는 아직 없다**
     (2026-08-27 자체 리뷰). 「열람은 안 막는다」를 실제로 하려면 그런
     경로를 만들어야 한다 — 지금은 감사 도구와 시험만 그 갈래를 쓴다.

    ★`AppError` 의 하위로 둔다 — 소비하는 자리가 넷이라 각자 감싸면
     한 곳이 빠지고, 그 경로만 사용자에게 다른 모양으로 나간다.
    c                8    t         |   dt         |d       y )Nstep.contract_violation.i  codemessagestatus_code)super__init___MODULE)selfr0   	__class__s     r   r3   zLegacyCarriedContract.__init__v   s%    +G95 	 	
r    )r0   r$   returnNone)__name__
__module____qualname____doc__r3   __classcell__)r6   s   @r   r+   r+   c   s    $
 
r    r+   c                      e Zd ZdZy)_CarriedAbortedu   carried 팬아웃 내부 신호 — 다른 묶음이 이미 실패해 **보내지 않았다**.

    밖으로 새지 않는다: 부르는 자리가 삼키고 원래 예외를 올린다.
    N)r9   r:   r;   r<    r    r   r?   r?   ~   s    r    r?   c                    | xs g D ch c]Q  }t        |t              r?|j                  d      r.|j                  d      dk(  rt        |j                  d            S c}S c c}w )u  VE 행에서 **인물 short_id 집합**을 뽑는다.

    ★`entity_type` 은 그 행이 이미 들고 있다 — 엔티티 지도를 한 번 더
     타지 않는다. 에피소드 링크로 만든 지도를 거치면 링크가 없는 인물이
     조용히 빠진다.
    short_identity_type	character)
isinstancedictr%   r$   )	ve_detailvs     r   char_sids_ofrI      sc     /r/!Aa155#4EE- K/ 	AEE*!  s   AA"c           
        t        |      sy|xs i j                  d      xs g D cg c]  }t        |t              s| }}|sy|D cg c]?  }t	        |j                  d      xs d      j                         s|j                  d      A }}|D cg c][  }t	        |j                  d      xs d      j                         r-t	        |j                  d            |vr|j                  d      ] }}|s|syt        j                  d| t        |      |xs d|xs dt        |      xs d       yc c}w c c}w c c}w )	u&  붙이지 못한 인물을 **로그로 남긴다** (2026-08-27 자체 리뷰).

    ★드롭 자체는 옳다 — 모르는 사람을 넣으면 이 판이 막으려던 것이
     그대로 돌아온다. 문제는 **조용한 것**이다. 셋을 구분할 수 없다:

       ㉠ 이 샷에 정말 사람이 없다
       ㉡ VE 가 아직 안 만들어졌다 (실측: 선택 샷 3,750개 중 124개가 빈다)
       ㉢ 신원이 안 맞는다 — 변형 인물이 대표적이다.
          DB 실측: `민숙`=C02 인데 `민숙 (변형 상태)`=C14 로 **다른 id** 다.
          그 샷 VE 에 변형만 있으면 저작이 낸 원본 이름은 안 맞는다.
          이름에서 접미사를 떼는 것은 글자 판단이라 안 한다 — 관계로
          잇는 것은 별건이다.
    Npeoplecharacter_short_idr"   character_koui   carried[%s]: 인물 %d명 중 안 붙인 것 — 신원 미해소 %s · 그 샷 배정 밖 %s (배정=%s)u   없음u   비어 있음)
r)   r%   rE   rF   r$   striploggerinfolenr   )tagr(   visible_short_idsprK   
unresolvedoffs          r   report_dropped_peoplerW      s>     #3')28b8P8AJq$<Oa8FP17 IAQUU#78>B?EEG %%'J I*0 J&Q!%%,-34::<155-./7HH 55 &C J #
KK	,S[*0#/ !4_	 QIJs   D5D5AD:A D?named_v1c                p    t        | j                  d      xs d      j                         }|r| d| S |S )u  `state_en` 을 **그 사람의 정본 표기에 묶어** 한 문장으로 만든다.

    ## 왜 (2026-08-29 실측, S2sh6)

    저작은 사람마다 `character_ko`·`character_short_id` 를 **typed 로**
    주고, 이 모듈은 `visible_short_ids` 로 그것을 대조까지 한다. 그런데
    문장을 만들 때 그 id 를 버리고 `state_en` 만 이어 붙였다. 실물:

        objects_en          … The fallen cane remains beside the prone figure.
        people[0] 노인 C03   'He remains on his side … wearing a gray coat …'
        people[1] 민수 C01   'He wears navy coveralls … He kneels …'

    앞 문장이 노인을 세워 놓은 뒤 `He` 가 셋 이어지니 **둘 다 노인으로**
    읽힌다. 그 프롬프트로 그린 재생성본은 민수를 **노인의 회색 코트**로
    그렸다.

    ★**대명사를 고쳐 쓰지 않는다.** 저작 문안은 한 글자도 안 건드리고,
     앞에 **누구인지만** 붙인다 — 재작성은 뜻을 바꿀 수 있고, 이 저장소는
     의미 판단을 코드가 하지 않는다.

    ★이름이 비면 **종전 그대로** 문장만 낸다. 없는 이름을 지어내지 않는다.
    rM   r"   : )r$   r%   rN   )personstatenames      r   _named_stater^      s=    . vzz.)/R0668D!%dV2eW050r    T)strictc                  | syt        |       s=t        | j                  d      xs d      j                         }|r|rt	        d      |S g }t        | j                  d      xs d      j                         }|r|j                  |       |s| j                  d      xs g D ]  }t        |t              st        |j                  d      xs d      j                         }t        |j                  d      xs d      j                         }	|so|	sr||v sw|j                  t        ||	              t        | j                  d      xs d      j                         }
|
r|j                  |
       d	j                  |      S )
ug  그 샷에 **실제로 나갈** CARRIED 본문을 만든다.

    조립 끝점이 넷이라(최종 스틸·마커 맵 둘·콘티) 같은 계약을 네 번
    손으로 쓰면 한 곳이 빠진다. **여기 한 곳만** 둔다.

    순서는 `objects → visible people → offscreen effects` 로 고정한다.

    Args:
        visible_short_ids: 그 샷에 **확정 배정된** 인물 short_id.
            ★`ve_ids_for_shot_ex` 의 씬 합집합 fallback(`exact=False`)을
             여기 넣으면 안 된다 — 그 추측은 PEOPLE 절의 배타 조항을
             뗄지 정하는 용도이지 **사람을 넣을 권한이 아니다.**
        bg_only: 무인 샷이면 사람 칸을 통째로 안 붙인다.
        strict: 옛 한 칸 값을 만났을 때 멈출지. 그림을 사는 경로는 참,
            열람·감사 경로는 거짓.
    r"   
carried_enu   carried 가 옛 한 칸 계약이다 — 이 값은 그 샷에 없는 인물을 말할 수 있어 새 그림에 쓸 수 없다(감사 1-B). `shot_continuity` 를 force 로 다시 돌릴 것.
objects_enrK   rL   state_enoffscreen_effects_en )
r)   r$   r%   rN   r+   appendrE   rF   r^   join)r(   rS   bg_onlyr_   legacypartsobjectsrT   sidr\   effectss              r   carried_text_for_shotrn      sX   . "3'SWW\*0b1779f'E 
 E#'','-2.446GW"(b(Aa&aee017R8>>@Cj)/R0668E u(9!9\!U34 ) #''017R8>>@GW88E?r    c                   | xs i j                  |      xs i }t        |      s/d|xs i j                  d      xs |j                  d      xs di}n|st        |||       t        ||||      S )u<  저장된 연속성에서 그 샷의 CARRIED 본문을 뽑는다.

    **소비하는 자리가 넷이라(최종 스틸·마커 맵 둘·콘티) 여기 한 곳만
    둔다.** 옛 계약의 `pose_fix` 병합까지 포함한다.

    ★옛 계약에서는 `fix.carried_en or carried[tag].carried_en` 로 두 값을
     골랐고, 그래서 **`pose_fix` 가 일부러 비운 칸이 옛 값으로
     되살아났다**(2026-08-27 Codex 지적). 새 계약에서는 `pose_fix` 가
     교정본을 `carried` 안 제자리에 넣으므로 읽을 곳이 한 군데다.
    ra   r"   )rS   rh   r_   )r%   r)   rW   rn   )carried_maprR   pose_fix_rowrS   rh   r_   r(   s          r   carried_clause_forrr     s    & "
!
!#
&
,"C"3'|1r66|D =!$!6=:<?c3(9: 0' r    i`	           r   )prompt_versioncall_structured_fnproject_configopik_metadatac                V  =>?@ABCD ddl m} |t        |      }	i xs i t         dddit         dddit         dddiit	        | d	 
      }
|
D cg c]&  }t        t        |d         t        |d               ( }}|sg i i dS t        ||
      D ci c]  \  }}||j                  d      xs d c}}Ct	        |
D ch c]  }t        |d          c}      }dj                  fd|D              }dj                  Cfd|D              }t        t        d|	      }t        t        dd|	      }d}d}|t        v r5|r3dj                  d t	        |      D              }d| }t        |      r|}d| d| | } t         d|||t         dt        t        	      }t!        |      }g }|j                  d      xs g D ]  DDj                  d      xs g D cg c]	  }||v s| }}Dj                  d      xs g D cg c]	  }||vs| }}|r&t"        j%                  d|Dj                  d             Dj                  d      xs d}|j'                  ||j                  |      Dj                  d       xs d|Dj                  d!      xs dd"        t        t        d#|	      Bt        t        d$d|	      Ad| d%| |z   ?t)        dt+        |      t,              D cg c]  }|||t,        z     c}@dL?@ABCfd&>t/        j0                         =dL=>fd'}i }t+        @      d(k  r5 >|      j                  d)      xs g D ]  DD|Dj                  d*      <    ndd+lm} m}! dd,lm}" dd-lm}#  |# |"|            }$ | tA        tB        t+        @            .      5 }%@D &ci c]  }&|%jE                  |$|&      |& }'}&d}( |!|'      D ]Y  })|'|)   }&	 |)jG                         }*t!        |&      }-|*j                  d)      xs g D ]  DDj                  d*      |-v sD|Dd*   <     [ |(|(	 ddd       |D cg c]	  }||vs| }.}|.rtO        d/t         d0|. d12      t        |      ri }/g }0|D ]  }g }1||   j                  d3      xs g D ]  }2tQ        |2tR              stU        |2j                  d      xs d      jW                         }|j                  |      }3|3s|0j'                  | d4|        |1j'                  ||3tU        |2j                  d5      xs d      jW                         tU        |2j                  d!      xs d      jW                         d6        tX        tZ        d7tU        ||   j                  d7      xs d      jW                         d3|1d8tU        ||   j                  d8      xs d      jW                         d!tU        ||   j                  d!      xs d      jW                         i|/|<    |0rct"        j%                  d9t+        |0      |0dd:        n?|D ci c]4  }|||   j                  d;      xs d||   j                  d!      xs dd<6 }/}t        t        d=|	      }4t        t        d>d|	      }5i }6t        |      }7|D ]P  DDd   D ]D  }8d}9|7r4t]        Dfd?|/|8   j                  d3      xs g D        d      }9|96|9d5   }:n|/|8   d;   }:d@Dd    dADd     dBC|8    dC|7rdD|: ndE|: z   }; t         d|4|;|5t         dF      }*|9~tU        |*j                  d5      xs d      jW                         }<|<r|<|9d5<   nt"        j%                  dG|8Dd          |*j                  dH      xs d|*j                  dI      xs ddJ|6|8<   |*j                  dH      xs d|*j                  dI      xs d|*j                  d;      xs ddK|6|8<   G S ||/|6dS c c}w c c}}w c c}w c c}w c c}w c c}w c c}&w # tH        $ r Y `tJ        $ r6}+|()|+}(=j!                          |'D ]  },|,jM                           Y d}+~+d}+~+ww xY w# 1 sw Y   BxY wc c}w c c}w )Mu,  연속성 3종 저작 → 체크포인트 payload.

    Returns:
        {"pose_canon": [{character_ko, character_short_id, pose_en, shots,
                          basis_ko}],
         "carried": {tag: {carried_en, basis_ko}},
         "pose_fix": {tag: {movement_en, figures_en, carried_en}}}
    Nr   )call_structured_pose_canonmodelgpt_carried	_pose_fixc                :    t        | d         t        | d         fS )Nscene_index
shot_index)int)ss    r   <lambda>z%run_shot_continuity.<locals>.<lambda>s  s    c!M"23S<5IJr    )keyr   r   )
pose_canoncarriedpose_fixdescriptionr"   z

c           
   3  t   K   | ]/  }d | dj                  |d       dj                  |d        1 yw)u   [씬 z] r"   
N)r%   ).0siscene_headingsscene_textss     r   	<genexpr>z&run_shot_continuity.<locals>.<genexpr>}  sF      B t2n((R01KOOB4K3LMs   58r   c              3  2   K   | ]  }| d |      ywrZ   Nr@   r   tdesc_by_tags     r   r   z&run_shot_continuity.<locals>.<genexpr>  s"     ADqQCr+a.!12D   pose_canon_system)versionpose_canon_schemac              3  &   K   | ]	  }d |   yw)z- Nr@   )r   r]   s     r   r   z&run_shot_continuity.<locals>.<genexpr>  s      
$>DbK$>s   u   

등장인물 정본 명단:
u   씬 원문 전문:

u   

샷 목록(시간순):
rx   schema_namery   timeoutnum_retriesimmobileshotsu?   shot_continuity pose_canon: 미지 샷 제거 %s (character=%s)rM   pose_enbasis_ko)rM   rL   r   r   r   carried_systemcarried_schemau9   

샷 목록(시간순 — 각각 carried state 판정):
c                    }t              dkD  r |ddj                  fd| D              z   z  } t         d|	t         dt        t              dkD  rt        	      S t
        	      S )N   u{   

이번 답의 대상 샷 — 이 목록의 샷만 출력한다(위 전체 목록은 시간순·소급 판단용 맥락):
r   c              3  2   K   | ]  }| d |      ywr   r@   r   s     r   r   z=run_shot_continuity.<locals>._carried_call.<locals>.<genexpr>  s"      I5aA3bQ(8!95r   r   r   )rQ   rg   r4   GLOBAL_AUTHOR_TIMEOUT_SECONDSCARRIED_CHUNK_RETRIESGLOBAL_AUTHOR_RETRIES)
chunkuserca_base	ca_chunks	ca_schemaca_sysrw   r   ry   rx   s
     r   _carried_callz*run_shot_continuity.<locals>._carried_call  s    y>A Tyy I5 IIJ KD "ix )")8,'125i.12D.
 	
 4
 	
r    c                    j                         r
t               	  |       S # t        $ r j                           w xY w)ub   중단 표가 서 있으면 **보내기 전에** 선다 — 다음 묶음을 더 사지 않는다.)is_setr?   BaseExceptionset)r   _carried_abortr   s    r   _send_carried_chunkz0run_shot_continuity.<locals>._send_carried_chunk  sH      "!##	 '' 	  		s	   % A r   itemsshot)ThreadPoolExecutoras_completed)bind_current_research_budget)bind_current_trace)max_workersr-   u   carried state 누락 샷: i  r.   rK   :rc   )rM   rL   rc   r   rb   rd   uw   shot_continuity carried: 정본 명단에 없는 이름 %d건 — 기록만 하고 프롬프트에 넣지 않는다: %s   ra   )ra   r   pose_fix_systempose_fix_schemac              3  p   K   | ]-  }t        |t              r|j                  d       d    k(  r| / yw)rM   N)rE   rF   r%   )r   rT   its     r   r   z&run_shot_continuity.<locals>.<genexpr>[  s:      F @1"1d+~."^2DD  @s   36u   자세 정본(z): u   

샷 텍스트: z

movement: 

figures: 

zstate: z	carried: )rx   r   ry   uN   shot_continuity pose_fix[%s/%s]: 교정본이 비어 저작본을 유지한다movement_en
figures_en)r   r   )r   r   ra   )r   z	List[str]r7   Dict[str, Any])/app.modules.llm.llm_clientr{   r   r4   r   r   r   zipr%   rg   r
   r   _NAME_ROSTER_PACKSr   r   r   r   rO   warningrf   rangerQ   CARRIED_CHUNK_SIZE	threadingEventconcurrent.futuresr   r   app.core.research_call_budgetr   app.modules.llm.opik_tracer   minCARRIED_CHUNK_WORKERSsubmitresultr?   r   cancelr	   rE   rF   r$   rN   r&   r'   next)Er   r   r   char_name_to_shortrv   rw   rx   ry   r{   resolvedorderedr   tagsr   	scene_ids
scenes_txt	shots_txtpc_sys	pc_schemacarried_rosterroster_block
roster_txtpc_userpc_restag_setr   knownunknownr]   ir   ca_gotr   r   r   r   sendpoolr   futs	first_excfresexcgownmissingr   rU   rK   rT   rl   pf_sys	pf_schemar   people_scopedrR   targetsubjectr   _fixedr   r   r   r   r   r   r   r   sE    ``  ```                                                     @@@@@@@@r   run_shot_continuityr   Q  s	   & !>,%n5HR);'5!1)8w.)9/	N JG JQQAF3q'(#ao*>?DQ RR@@47g4F4FDAqAEE- &B&4FK w?w!Am,-w?@I  J 		ADAAI "5xHF$dHI NL++0BYY 
$*+=$>
 

 ;:,G#N3)N'
|-i[HG);%i{+#-)F $iG')Jjj$**FF7O1r1B1qQ'\1B ffWo33H3q7G13HNNQ/ vvn%+ $&8&<&<T&B66),2FF:.4"		
 +* "2HEFG%5tXNI'
|Mi[Z G
  3t9.@ACAQ a../ACI
 
, __&N
  F
9~%))'28b8B%'F266&>" 9 	HNA "">?R"ST13y>B
AJKDKKe,e3DK15I
 "$'Q
((*C %j'''*0b0Bvvf~,-/r&z* 1 ($ $ %7
: 2$Q!6/q$G2+G950	:
 	

  /  "
AFAY]]8,22!!T*15506B7==?(,,T2%%1TFm4$( +. #AEE*$5$; < B B D #AEE*$5$; < B B D  3  %&=c&)--"="CDJJL&&1IMM"89?R)AAFCq	j 9 ?R@FFHGAJ# 2 NNHJCR 

 	 $QimmL9?R"1IMM*5;   	 
 "3XFF"D(I +-H,^<Mg;C/3F F 0 0 : @b @ FGKM > ,!#,|4 N!3 4C9 G""-c"2!3 4 !
 +8WWI&#G9-/  %)9%-&iy1+C ! SWWZ06B7==?)/F:&NN458"^:LN $'77=#9#?R"%'',"7"=2! "ww}5;!ggl39r!ggl39rHSMw  D %hOOA	 R @f CH2Cl L ' $  ($'	&**,!%AHHJ "&
 
: 3X
s    +`#$ `(`.5	`3?`3	`8&`8`=ba'b<a6bb 	b!*b!9b&b	bbb+bbbbb)r   r$   r7   r$   )r   r$   r7   r#   )r(   Optional[Dict[str, Any]]r7   r#   )rG   z'list'r7   
'set[str]')rR   r$   r(   r   rS   r   r7   r8   )r[   r   r\   r$   r7   r$   )
r(   r   rS   r   rh   r#   r_   r#   r7   r$   )rp   r   rR   r$   rq   r   rS   r   rh   r#   r_   r#   r7   r$   )r   zList[Dict[str, Any]]r   Dict[int, str]r   r  r   zDict[str, str]rv   r$   rw   z'Optional[Callable[..., Dict[str, Any]]]rx   r   ry   r   r7   r   )-r<   
__future__r   loggingr   typingr   r   r   r   r   app.core.errorsr	   app.modules.prompt_loaderr
   r   &app.modules.pipeline.shot_ref_classifyr   	getLoggerr9   rO   r4   r   r   r   r&   r'   r   r   r)   r+   	Exceptionr?   rI   rW   !CARRIED_PERSON_PROJECTION_VERSIONr^   rn   rr   r   r   r   r   r   r   r@   r    r   <module>r     s  0 #   6 6 $ > 9			8	$
 

 
 
# * 3Z   
 * % 
.
	$
H 
6i !	!+!@J!	!R %/ !1@ 4	!4 "4 	4
 4 	4| )	 +
 "   	X !%     
   BF/3.2DPDP  DP #	DP
 'DP DP @DP -DP ,DP DPr    