
    [i^                        d Z ddlZddlZddlZddlZddlZddlmZ ddlm	Z	m
Z
 ddlZdZej                  j                  de       ddlmZmZmZ ddlmZ  ej,                  de d      Z ej0                  e      Zej4                  j7                  e       	 	 	 	 	 dd	efd
Z G d d      Z G d d      Z G d d      Z  G d d      Z! G d d      Z" G d d      Z# G d d      Z$y)u$  
테스트: test_task_180_1.py
대상:
  1. /home/jay/workspace/prompts/team_prompts.py :: _build_glm_prompt()
  2. /home/jay/workspace/scripts/check-dev3.py (check_openclaw, check_paths,
     scan_event_files, calc_stats, --json / --quick CLI)
작성자: 아르고스 (테스터, dev1-team)
    N)Path)	MagicMockpatchz/home/jay/workspace)_build_glm_prompt	TEAM_INFOWORKSPACE_ROOT
check_dev3/scripts/check-dev3.pyreturnc                     t         d   }d}dt         d|  d| d|d d  d	}dt         d|  }t         d	|  d
}	t        ||| |||||	||
      S )Nz	dev3-teamzpython3 z/memory/task-timer.py start z --team z	 --desc "   "z/memory/task-timer.py end z/memory/reports/z.md)
teamteam_idtask_id	task_descleveltimer_start	timer_endreport_path
project_idchain_id)r   r   r   )
r   r   r   r   r   r   r   r   r   r   s
             1/home/jay/workspace/teams/dev1/test_task_180_1.py_make_glm_promptr   )   s     [!DG^,,H	QYZaYbblmvwzxzm{l||~K>**DWINI#$$4WISAK     c                   X    e Zd ZdZd Zd Zd Zd Zd Zd Z	d Z
d	 Zd
 Zd Zd Zd Zy)TestBuildGlmPromptu$   _build_glm_prompt() 단위 테스트c                 4    t        dd      }d|v sJ d       y)u0   프롬프트에 task_id 가 포함돼야 한다.
task-180.1u   API 서버 구축)r   r   u"   task_id 가 프롬프트에 없음Nr   selfprompts     r   test_contains_task_idz(TestBuildGlmPrompt.test_contains_task_idN   s#    !,BUVv%K'KK%r   c                 6    d}t        |      }||v sJ d       y)u2   프롬프트에 task_desc 가 포함돼야 한다.u   API 서버 구축 및 테스트)r   u$   task_desc 가 프롬프트에 없음Nr    )r"   descr#   s      r   test_contains_task_descz*TestBuildGlmPrompt.test_contains_task_descS   s#    0!D1v~EEE~r   c                 P    d}t        |      }t         d}||v sJ d| d       y)u6   프롬프트에 log_dir 경로가 포함돼야 한다.r   r   z/teams/dev3/logsz	log_dir (   ) 가 프롬프트에 없음Nr   r   )r"   r   r#   log_dirs       r   test_contains_log_dirz(TestBuildGlmPrompt.test_contains_log_dir\   s<    !'2#$$45& SIgY6R"SS r   c                 V    d}t        |      }t         d| d}||v sJ d| d       y)u7   프롬프트에 log_file 경로가 포함돼야 한다.r   r)   z/teams/dev3/logs/z.logz
log_file (r*   Nr+   )r"   r   r#   log_files       r   test_contains_log_filez)TestBuildGlmPrompt.test_contains_log_filec   sB    !'2$%%6witD6!VZz9U#VV!r   c                 D    t               }d|v sJ d       d|v sJ d       y)uU   프롬프트에 '1차 타임아웃' 과 '재시도' 키워드가 포함돼야 한다.u   1차 타임아웃u$   '1차 타임아웃' 키워드 없음u	   재시도u   '재시도' 키워드 없음Nr    r!   s     r   $test_contains_timeout_retry_keywordsz7TestBuildGlmPrompt.test_contains_timeout_retry_keywordsm   s2    !#"f,T.TT,f$D&DD$r   c                 l    d}t        |      }t         d| d}||v sJ d| d       d|v sJ d       y	)
uP   프롬프트에 .failed 파일 경로와 cokacdir 명령이 포함돼야 한다.r   r)   z/memory/events/z.failedzfailed_file (u   ) 경로 없음cokacdiru   cokacdir 명령어 없음Nr+   )r"   r   r#   failed_files       r   &test_contains_failed_file_and_cokacdirz9TestBuildGlmPrompt.test_contains_failed_file_and_cokacdirv   sT    !'2'(yHf$Rk]/&RR$V#@%@@#r   c                 D    t               }d|v sJ d       d|v sJ d       y)uM   GLM 메시지에 오류 핸들링 및 mkdir -p 지시가 포함돼야 한다.u   오류u   오류 관련 문구 없음zmkdir -pu   mkdir -p 지시 없음Nr    r!   s     r    test_contains_glm_error_handlingz3TestBuildGlmPrompt.test_contains_glm_error_handling   s2    !#6!@#@@!V#=%==#r   c                 V    d}t        |      }t         d| d}||v sJ d| d       y)uG   done 파일 경로가 teams/dev3/{task_id}.done 형식이어야 한다.r   r)   z/teams/dev3/z.doneu   done 파일 경로 (   ) 없음Nr+   )r"   r   r#   expected_dones       r   test_done_file_path_correctz.TestBuildGlmPrompt.test_done_file_path_correct   sA    !'2)*,wiuE&V*>}oX(VV&r   c                 `    d}t        |      }d|v sJ d       t         d| d|v sJ d       y)	uN   project_id 가 주어지면 프로젝트 격리 규칙이 포함돼야 한다.z
proj-alpha)r   u   프로젝트 격리u!   프로젝트 격리 문구 없음z
/projects//u   프로젝트 경로 없음Nr+   )r"   r   r#   s      r   &test_project_isolation_with_project_idz9TestBuildGlmPrompt.test_project_isolation_with_project_id   sG    !
!Z8$.S0SS. !J<q9VCaEaaCr   c                 p    d}d}t        ||      }d|v sJ d       ||v sJ d| d       d|v sJ d	       y
)uM   chain_id 가 주어지면 체인 완료 알림 명령이 포함돼야 한다.zchain-99r   )r   r   zchain.pyu   chain.py 명령 없음z
chain_id (r:   	task-doneu    task-done 서브커맨드 없음Nr    )r"   r   r   r#   s       r   %test_chain_notification_with_chain_idz8TestBuildGlmPrompt.test_chain_notification_with_chain_id   s\    !'HEV#=%==#6!BZz#BB!f$H&HH$r   c                 2    t        d      }d|vsJ d       y)uR   chain_id 가 None 이면 프롬프트에 체인 알림 명령이 없어야 한다.N)r   rA   u0   chain_id 없는데 task-done 명령이 포함됨r    r!   s     r   +test_no_chain_notification_without_chain_idz>TestBuildGlmPrompt.test_no_chain_notification_without_chain_id   s     !40&(\*\\(r   c                 D    t               }d|v sJ d       d|v sJ d       y)uH   프롬프트에 FOUND 변수와 seq 1 120 지시가 포함돼야 한다.FOUNDu   FOUND 변수 없음z	seq 1 120u   seq 1 120 없음Nr    r!   s     r   test_timeout_scenario_detailsz0TestBuildGlmPrompt.test_timeout_scenario_details   s2    !#& 7"77 f$8&88$r   N)__name__
__module____qualname____doc__r$   r'   r-   r0   r2   r6   r8   r<   r?   rB   rD   rG    r   r   r   r   H   sK    .
L
FTWEA>WbI]9r   r   c                   .    e Zd ZdZd Zd Zd Zd Zd Zy)TestCheckOpenclawu:   check_openclaw() 단위 테스트 (subprocess mock 사용)c                 *   t               }d|_        d|_        t               }d|_        d|_        d|_        t	        d||g      5  t
        j                         }ddd       d   d	u sJ |d
   dk(  sJ |d   dk(  sJ |d   J y# 1 sw Y   .xY w)uK   which openclaw 성공 + --version 성공 → available=True, version 설정r   z/usr/local/bin/openclaw
zopenclaw 1.2.3
 subprocess.runside_effectN	availableTpathz/usr/local/bin/openclawversionzopenclaw 1.2.3errorr   
returncodestdoutstderrr   r	   check_openclawr"   which_resultversion_resultresults       r   test_openclaw_availablez)TestCheckOpenclaw.test_openclaw_available   s     {"#9"$%! 2 "#,1OP 	1..0F	1 k"d***f~!::::i $4444g&&&	1 	1s   B		Bc                     t               }d|_        d|_        t        d|      5  t        j                         }ddd       d   du sJ |d   J y# 1 sw Y   xY w)	u8   which openclaw 실패(returncode!=0) → available=False   rP   rQ   )return_valueNrT   FrU   r   rY   rZ   r   r	   r\   )r"   r^   r`   s      r   test_openclaw_not_foundz)TestCheckOpenclaw.test_openclaw_not_found   sl     {"# #,? 	1..0F	1 k"e+++f~%%%		1 	1s   AAc                     t        dt        d            5  t        j                         }ddd       d   du sJ |d   J d|d   v sJ y# 1 sw Y   #xY w)uI   subprocess.run 이 FileNotFoundError 를 던지면 error 필드에 기록rQ   zwhich not foundrR   NrT   FrW   )r   FileNotFoundErrorr	   r\   )r"   r`   s     r   "test_openclaw_subprocess_exceptionz4TestCheckOpenclaw.test_openclaw_subprocess_exception   sn    #1BCT1UV 	1..0F	1 k"e+++g*** F7O333	1 	1s   AAc                    t               }d|_        d|_        t               }d|_        d|_        d|_        t	        d||g      5  t
        j                         }ddd       d	   d
u sJ |d   dk(  sJ y# 1 sw Y   xY w)uM   which 성공 + --version returncode!=0 → available=True, version 은 stderrr   /usr/bin/openclaw
rc   rP   zunknown optionrQ   rR   NrT   TrV   rX   r]   s       r   test_openclaw_version_failsz-TestCheckOpenclaw.test_openclaw_version_fails   s     {"#3"$%! " 0#,1OP 	1..0F	1 k"d***i $4444		1 	1s   A88Bc                     t               d_        d_        fd}t        d|      5  t        j                         }ddd       d   du sJ |d	   J y# 1 sw Y   xY w)
uH   which 성공 + --version TimeoutExpired → available=True, error 설정r   rk   c                 <    d| v rS t        j                  | d      )Nwhich   )
subprocessTimeoutExpired)cmdkwargsr^   s     r   rS   zDTestCheckOpenclaw.test_openclaw_version_timeout.<locals>.side_effect  s#    #~##++C33r   rQ   rR   NrT   TrW   re   )r"   rS   r`   r^   s      @r   test_openclaw_version_timeoutz/TestCheckOpenclaw.test_openclaw_version_timeout	  st     {"#3	4
 #= 	1..0F	1 k"d***g***		1 	1s   AA#N)	rH   rI   rJ   rK   ra   rf   ri   rl   ru   rL   r   r   rN   rN      s    D
',
&45(+r   rN   c                   .    e Zd ZdZd Zd Zd Zd Zd Zy)TestCheckPathsu'   check_paths() 테스트 (실제 환경)c                     t         j                         }t        |t              sJ t	        |      dkD  sJ |D ]  }d|v sJ d|v sJ d|v sJ d|v rJ  y)uG   결과가 리스트이고 각 항목에 필수 키가 있어야 한다.r   labelrU   exists
suggestionN)r	   check_paths
isinstancelistlenr"   checksitems      r   test_returns_list_of_dictsz)TestCheckPaths.test_returns_list_of_dicts  ss    '')&$'''6{Q 	(Dd?"?T>!>t###4'''		(r   c                 f    t         j                         }|D cg c]  }|d   	 }}d|v sJ yc c}w )u7   dev3 작업 디렉토리 항목이 포함돼야 한다.ry   u   dev3 작업 디렉토리Nr	   r|   r"   r   clabelss       r   test_dev3_dir_check_presentz*TestCheckPaths.test_dev3_dir_check_present)  s:    '')&,-!G*--)V333 .   .c                 f    t         j                         }|D cg c]  }|d   	 }}d|v sJ yc c}w )u2   events 디렉토리 항목이 포함돼야 한다.ry   u   events 디렉토리Nr   r   s       r   test_events_dir_check_presentz,TestCheckPaths.test_events_dir_check_present/  s:    '')&,-!G*--$... .r   c                 d    t         j                         }|D ]  }t        |d   t              rJ  y)u-   exists 필드는 bool 타입이어야 한다.rz   N)r	   r|   r}   boolr   s      r   test_exists_is_booleanz%TestCheckPaths.test_exists_is_boolean5  s3    '') 	4Dd8nd333	4r   c                     t         j                         }t        d |D        d      }|J d       |d   s|d   J d|d   v sJ yy)uX   로그 디렉토리가 없을 경우 suggestion 에 mkdir 명령이 포함돼야 한다.c              3   2   K   | ]  }|d    dk(  s|  yw)ry   u   dev3 로그 디렉토리NrL   ).0r   s     r   	<genexpr>zFTestCheckPaths.test_suggestion_for_missing_logs_dir.<locals>.<genexpr>>  s     Xqz=W/W!Xs   Nu&   dev3 로그 디렉토리 항목 없음rz   r{   mkdir)r	   r|   next)r"   r   	log_checks      r   $test_suggestion_for_missing_logs_dirz3TestCheckPaths.test_suggestion_for_missing_logs_dir;  sf    '')XVXZ^_	$N&NN$"\*666i5555 #r   N)	rH   rI   rJ   rK   r   r   r   r   r   rL   r   r   rw   rw     s    1	(4/46r   rw   c                   4    e Zd ZdZd Zd Zd Zd Zd Zd Z	y)	TestScanEventFilesu,   scan_event_files() 테스트 (실제 환경)c                 P    t         j                         }t        |t              sJ y)u$   반환값은 리스트여야 한다.N)r	   scan_event_filesr}   r~   r"   recordss     r   test_returns_listz$TestScanEventFiles.test_returns_listH  s     --/'4(((r   c                     t         j                         }h d}|D ]*  }|t        |j                               z
  }|s"J d|         y)uW   각 레코드에 task_id, status, mtime, mtime_str, has_report 키가 있어야 한다.>   mtimestatusr   	mtime_str
has_reportu   레코드에 키 누락: N)r	   r   setkeys)r"   r   requiredrmissings        r   "test_each_record_has_required_keysz5TestScanEventFiles.test_each_record_has_required_keysM  sO    --/L 	FAQVVX.GE";G9 EE;	Fr   c                 b    t         j                         }|D ]  }|d   dv rJ d|d            y)u3   status 값은 'done' 또는 'failed' 여야 한다.r   )donefailedu   잘못된 status: N)r	   r   )r"   r   r   s      r   test_status_values_validz+TestScanEventFiles.test_status_values_validU  sE    --/ 	YAX;"44X8J1X;-6XX4	Yr   c                     t         j                         }|D cg c]  }|d   	 }}t        |      t        t        |            k(  sJ d       yc c}w )u5   반환 결과에 중복 task_id 가 없어야 한다.r   u   중복 task_id 존재N)r	   r   r   r   )r"   r   r   task_idss       r   test_no_duplicate_task_idsz-TestScanEventFiles.test_no_duplicate_task_ids[  sM    --/*12QAiL228}CM 22K4KK2 3s   Ac                     t         j                         }t        |      dk\  r*|D cg c]  }|d   	 }}|t        |d      k(  sJ d       yyc c}w )u4   결과는 mtime 내림차순 정렬이어야 한다.   r   T)reverseu    mtime 내림차순 정렬 아님N)r	   r   r   sorted)r"   r   r   mtimess       r   test_sorted_by_mtime_descz,TestScanEventFiles.test_sorted_by_mtime_desca  sV    --/w<1*12Qaj2F2VFD99];]]9 2s   Ac                     t        j                  t        dt        d            5  t        j	                         }ddd       g k(  sJ y# 1 sw Y   xY w)u>   EVENTS_DIR 이 없으면 빈 리스트를 반환해야 한다.
EVENTS_DIRz/nonexistent/path/xyzN)r   objectr	   r   r   r   s     r   *test_returns_empty_when_events_dir_missingz=TestScanEventFiles.test_returns_empty_when_events_dir_missingh  sG    \\*lD9P4QR 	4 113G	4"}}	4 	4s   A

AN)
rH   rI   rJ   rK   r   r   r   r   r   r   rL   r   r   r   r   E  s'    6)
FYL^r   r   c                   :    e Zd ZdZd Zd Zd Zd Zd Zd Z	d Z
y	)
TestCalcStatsu   calc_stats() 단위 테스트c                     ddiddiddig}t         j                  |      }|d   dk(  sJ |d   dk(  sJ |d   dk(  sJ |d   d	k(  sJ y
)u4   전부 done 이면 success=total, failed=0, rate=100r   r   total   successr   r   rated   Nr	   
calc_statsr"   historystatss      r   test_all_donezTestCalcStats.test_all_doner  sv    f%&'9Hf;MN%%g.W~"""Y1$$$X!###V}###r   c                     ddiddig}t         j                  |      }|d   dk(  sJ |d   dk(  sJ |d   dk(  sJ |d   dk(  sJ y)	u&   전부 failed 이면 success=0, rate=0r   r   r   r   r   r   r   Nr   r   s      r   test_all_failedzTestCalcStats.test_all_failed{  so    h'(H)=>%%g.W~"""Y1$$$X!###V}!!!r   c                     ddiddiddiddig}t         j                  |      }|d   dk(  sJ |d   dk(  sJ |d   dk(  sJ |d   d	k(  sJ y
)u   2 done / 2 failed → rate=50r   r   r   r      r   r   r   2   Nr   r   s      r   
test_mixedzTestCalcStats.test_mixed  s     vx vx 	
 %%g.W~"""Y1$$$X!###V}"""r   c                 ~    t         j                  g       }|d   dk(  sJ |d   dk(  sJ |d   dk(  sJ |d   dk(  sJ y)u+   빈 이력이면 rate=0, 모든 카운트 0r   r   r   r   r   Nr   r"   r   s     r   test_empty_historyz TestCalcStats.test_empty_history  s[    %%b)W~"""Y1$$$X!###V}!!!r   c                 H    t         j                  ddig      }|d   dk(  sJ y)u   1건 done → rate=100r   r   r   r   Nr   r   s     r   test_single_donezTestCalcStats.test_single_done  s,    %%&'9&:;V}###r   c                 X    ddiddiddig}t         j                  |      }|d   dk(  sJ y)u0   1/3 → int(33.3) = 33 (반올림 아닌 절사)r   r   r   r   !   Nr   r   s      r   test_rate_truncates_not_roundsz,TestCalcStats.test_rate_truncates_not_rounds  s?    f%(';h=QR%%g.V}"""r   c                 Z    t         j                  g       }dD ]  }||v rJ d| d        y)u7   반환 dict 에 total, success, failed, rate 키 존재r   r   r   r   'u   ' 키 없음Nr   )r"   r   keys      r   test_stats_keys_presentz%TestCalcStats.test_stats_keys_present  s;    %%b)9 	7C%<61SE!66<	7r   N)rH   rI   rJ   rK   r   r   r   r   r   r   r   rL   r   r   r   r   o  s(    '$"#"$
#7r   r   c                   (    e Zd ZdZd Zd Zd Zd Zy)TestCliJsonu.   --json 플래그: 유효한 JSON 출력 검증c           	         t        j                  t        j                  t         ddgddd      }|j
                  dk(  s!J d|j
                   d|j                          	 t        j                  |j                        }dv sJ d|v sJ d|v sJ d|v sJ d|v sJ y# t        j                  $ r2}t        j                  d	| d
|j                  dd         Y d}~_d}~ww xY w)uP   --json 모드로 실행하면 stdout 이 파싱 가능한 JSON 이어야 한다.r
   --jsonT   capture_outputtexttimeoutr   exit code: 	
stderr: u   JSON 파싱 실패: u	   
출력: Ni  openclawpathsr   r   generated_at)rq   runsys
executable	WORKSPACErY   r[   jsonloadsrZ   JSONDecodeErrorpytestfail)r"   procdataes       r   test_json_output_is_valid_jsonz*TestCliJson.test_json_output_is_valid_json  s    ~~^^	{*@A8L	
 !#[{4??2C:dkk]%[[#	Q::dkk*D
 T!!!$D   $%%% ## 	QKK.qcDKK<M;NOPP	Qs   #B! !C&4(C!!C&c                     t        j                  t        j                  t         ddgddd      }t        j                  |j                        }|d   }dD ]  }||v rJ d| d	        y
)uK   JSON 출력의 stats 에 total/success/failed/rate 키가 있어야 한다.r
   r   Tr   r   r   r   u   stats 에 'u   ' 없음Nrq   r   r   r   r   r   r   rZ   )r"   r   r   r   r   s        r   test_json_stats_structurez%TestCliJson.test_json_stats_structure  su    ~~^^	{*@A8L	
 zz$++&W9 	=C%<<;se8!<<<	=r   c                     t        j                  t        j                  t         ddgddd      }t        j                  |j                        }t        |d   t              sJ y)u0   JSON 출력의 paths 는 리스트여야 한다.r
   r   Tr   r   r   N)
rq   r   r   r   r   r   r   rZ   r}   r~   r"   r   r   s      r   test_json_paths_is_listz#TestCliJson.test_json_paths_is_list  sW    ~~^^	{*@A8L	
 zz$++&$w-...r   c                     t        j                  t        j                  t         ddgddd      }t        j                  |j                        }d|d   v sJ y)	u>   JSON 출력의 openclaw 에 available 키가 있어야 한다.r
   r   Tr   r   rT   r   Nr   r   s      r   $test_json_openclaw_has_available_keyz0TestCliJson.test_json_openclaw_has_available_key  sV    ~~^^	{*@A8L	
 zz$++&d:....r   N)rH   rI   rJ   rK   r   r   r   r   rL   r   r   r   r     s    8&*=	/	/r   r   c                   .    e Zd ZdZd Zd Zd Zd Zd Zy)TestCliQuicku1   --quick 플래그: 환경 점검만 출력 검증c                     t        j                  t        j                  t         ddgddd      }|j
                  dk(  s!J d|j
                   d|j                          y	)
u/   --quick 모드는 exit code 0 이어야 한다.r
   --quickTr   r   r   r   r   N)rq   r   r   r   r   rY   r[   r"   r   s     r   test_quick_exits_zeroz"TestCliQuick.test_quick_exits_zero  s^    ~~^^	{*@A9M	
 !#[{4??2C:dkk]%[[#r   c                     t        j                  t        j                  t         ddgddd      }d|j
                  v sJ d       y)	u@   --quick 출력에 '환경 점검' 섹션이 포함돼야 한다.r
   r  Tr   r   u   환경 점검u    '환경 점검' 문자열 없음Nrq   r   r   r   r   rZ   r  s     r   $test_quick_output_contains_env_checkz1TestCliQuick.test_quick_output_contains_env_check  sI    ~~^^	{*@A9M	
 $++-Q/QQ-r   c                     t        j                  t        j                  t         ddgddd      }d|j
                  vsJ d       y)	uD   --quick 출력에 '최근 작업 이력' 섹션이 없어야 한다.r
   r  Tr   r   u   최근 작업 이력u)   --quick 인데 이력 섹션이 출력됨Nr  r  s     r   test_quick_output_no_historyz)TestCliQuick.test_quick_output_no_history  sI    ~~^^	{*@A9M	
 &T[[8e:ee8r   c                     t        j                  t        j                  t         ddgddd      }d|j
                  vsJ d       y)	u?   --quick 출력에 통계(성공률) 섹션이 없어야 한다.r
   r  Tr   r   u	   성공률u)   --quick 인데 통계 섹션이 출력됨Nr  r  s     r   test_quick_output_no_statsz'TestCliQuick.test_quick_output_no_stats	  sI    ~~^^	{*@A9M	
 $++-Z/ZZ-r   c                     t        j                  t        j                  t         ddgddd      }d|j
                  v sJ y)uE   --quick 출력 첫 줄에 헬스체크 제목이 포함돼야 한다.r
   r  Tr   r   zDev3 Team Health CheckNr  r  s     r   -test_quick_output_contains_health_check_titlez:TestCliQuick.test_quick_output_contains_health_check_title  sC    ~~^^	{*@A9M	
 (4;;666r   N)	rH   rI   rJ   rK   r  r  r	  r  r  rL   r   r   r   r     s"    ;\Rf[7r   r   )r   u   테스트 작업 설명normalNN)%rK   	importlibr   rq   r   tempfilepathlibr   unittest.mockr   r   r   r   rU   insertprompts.team_promptsr   r   r   importlib.utilutil_iluspec_from_file_location_specmodule_from_specr	   loaderexec_modulestrr   r   rN   rw   r   r   r   r   rL   r   r   <module>r     s       
   *  "	 9  N M $$$YK56	 #T""5)
    $ '
 	>o9 o9lZ+ Z+z'6 '6T' 'T:7 :7z9/ 9/x37 37r   