
    ViQ                        d dl mZmZ d dlmZ d dlmZ d dlmZm	Z	m
Z
mZmZmZmZmZmZ d dlmZmZmZmZmZmZmZmZ d dlZd dlmZ d dlmZ d d	lm Z  d dl!Z!d dl"Z"d dl#Z#d d
l$m%Z%  e#j&        e#j'                    e#j(        e)          Z* eddg          Z+ eddg          Z,dZ-e+.                    d          defd            Z/e+.                    d          de	fd            Z0e+.                    d          de
fd            Z1e+.                    d          de
fd            Z2e+.                    d          defd            Z3e,4                    d          de5fd            Z6e+4                    d          de5fd             Z7e+.                    d!          defd"            Z8e+.                    d#          defd$            Z9d d%l:m;Z;  G d& d'e;          Z<e+.                    d(          de<fd)            Z=e+4                    d*          d+e>fd,            Z?e,4                    d-          d.e5d/e5fd0            Z@e+.                    d1          d2             ZAe+.                    d3          de
fd4            ZBe+.                    d5          defd6            ZCe+.                    d7          defd8            ZDe+.                    d9          defd:            ZEe,4                    d;          d.e5d/e5fd<            ZFe+.                    d=          d>             ZGe+.                    d?          de	fd@            ZHe+.                    dA          defdB            ZIe+.                    dC          defdD            ZJe+4                    dE          dFe5fdG            ZKe+4                    dH          dFe5fdI            ZLe+4                    dJ          dFe5fdK            ZMe,4                    dL          dFe5fdM            ZNe,4                    dN          dFe5fdO            ZO G dP dQe;          ZPe+.                    dR          dePfdS            ZQdS )T    )	APIRouterHTTPException)curriculum_module)generate_ai_curriculum)	StartCurriculumRequestChatCurriculumRequestGetQuizRequestCheckQuizRequestCheckFEQuizRequestGenerateJournalRequestGetJournalRequestCertQuizRequestCheckCertQuizRequest)get_gemini_modelPPT_PATHCURRICULUM_PDF_PATHPROGRESS_PDF_PATHIMG_PATHIMG_EXP_PATH
IMG_Q_PATH
APP_PREFIXN)classify_and_save)save_daily_log)typesFileResponse)level 
Curriculum)prefixtagsFilesuU  
あなたは学習者の「親しい友人（Best Friend）」です。
以下のルールを絶対に守ってください：
1. **言語**: 日本語のみ使用。
2. **口調**: 絶対に敬語（〜です、〜ます）を使わないこと。「〜だよ」「〜じゃん」「〜だね」といった、仲の良い友達と話す「タメ口」を使うこと。
3. **態度**: 明るく、ポジティブに、絵文字（🔥, ✨, 💪, 😂など）を多用して会話すること。
4. **役割**: 先生ではなく、一緒に走るパートナーとして振る舞うこと。
z/startrequestc                   K   	 | j         }t          j        |          }|sdddS |d         }|d         }t          j        ||           t	          |          dvrdddS t          j        ||          }t          j        ||          }|sdd	dS |d
         }|r|d         nd}|r|d         nd}	|r|d         nd}
d| d| d| d|	 d|
 d| d}t                      }|j        	                    dt          j        dt          j        |          g          gt          j        t          d                    }t          |dd|j                   d {V  t#          |d |j                   d!|j        ||d"         d#S # t$          $ r@}t&                              d$|            t+          d%t	          |          &          d }~ww xY w)'Nerroru*   進捗データが見つかりません。)statusmessagecurrent_dayr&   )0NOT_STARTED	completedu0   本日の学習は既に完了しています。u6   本日のカリキュラムが見つかりません。namesummary_contentu   なしai_feedbackpraise_contentuu   
            あなたは学習者（親しい友人）のパートナーです。
            今日は学習 **Day u3   ** です。
            今日のテーマは「**u\   **」です。
            
            [昨日の振り返り]
            - 学習内容: u(   
            - AIフィードバック: u   
            - 称賛: u  
            
            これらを踏まえて、今日の学習を始めるユーザーに挨拶をしてください。
            
            【絶対ルール - 厳守すること】
            1. **分割出力**: 発言を短く切り、2〜3つの吹き出しに分けるため、文の区切りに「|||」を入れてください。
               (例: おっす！久しぶり！|||今日はこのテーマだね。|||準備はいい？)
            2. **短文**: 1つの吹き出しは短く、テンポよく。長文は禁止。
            3. **強調**: 重要な単語（Day数やテーマ名）は **太字** (例: **Day u  **) にして。
            4. **トーン**: 敬語禁止。親友のように明るく、絵文字を使って。
            5. **内容**: 昨日の頑張りを一言褒めて、今日のテーマの面白さを伝えて、最後に「準備はいい？」と聞く。
            gemini-2.5-flashusertextrolepartsg?)system_instructiontemperaturemodelcontentsconfigIC
session_idsenderpartr3   botstartitem_id)r&   r'   r(   rE   zStart Error:   status_codedetail)r@   r   get_user_progressinit_user_curriculumstrget_previous_feedbackget_today_item_infor   modelsgenerate_contentr   ContentPartGenerateContentConfigSYSTEM_PROMPTr   r3   r   	Exceptionloggerr%   r   )r#   r@   progressr(   r&   	prev_data
today_item	item_nameprev_summaryprev_feedbackprev_praisepromptclientresponsees                  %/app/app/routers/curriculum_router.pystart_curriculumrc   *   s     N<'
 %6zBB 	a&3_```}-(# 	.z;GGG v;;222)6hiii &;JTT	&::{SS
 	m&3klll v&	7@Ny!233h4=K	-0085>Li 011H#.  (1  *  )6  #   bm!  * "## =11$m
8O8O8O7PQQQR.#0   2 
 
  :cRZR_``````````z5(-888 }&!),	
 
 	
  < < <(Q(()))CFF;;;;<s)   !F :F !0F C3F 
G;GGz/chatc           	      p  K   	 t                      }| j        dk    rt          | j        dd| j                   d {V  t          | j        d| j                   d| j         d}|j                            dt          j	        dt          j
        |	          g
          gddi          }t          j        |j                  }t          | j        dd|                    dd                     d {V  t          | j        d|                    dd                     |S | j        dk    rt          | j        dd| j                   d {V  t          | j        d| j                   d| j         d}|j                            dt          j	        dt          j
        |	          g
          gddi          }t          j        |j                  }|d         r| j        }| j        }|^t!          d           t#          j        |          }	|	r9|	d         }
t#          j        ||
          }|r|d         }t!          d|            |rt#          j        ||          \  }}ng }t!          d           t!          d|            t!          d|rt+          |          nd            g }g }|rd |D             }t#          j        |          }|D ]d}|d         }d| }t!          d | d!|            |                    |d         |d"         |d#           |                    |d"                    et!          d$           |sd%d&g d'S d(                    |          }d)| d*t+          |           d+}|j                            dt          j	        dt          j
        |	          g
          g,          }d%|j        |d'S d-d.d/S | j        d0k    rt          | j        dd| j                   d {V  t          | j        d| j                   d| j         d1}|j                            dt          j	        dt          j
        |	          g
          gddi          }t          j        |j                  }|d         rQd2}|j                            dt          j	        dt          j
        |	          g
          g,          }d%|j        d/S d-d3d/S | j        d4k    rt          | j        dd| j                   d {V  t          | j        d| j                   d| j         d5}|j                            dt          j	        dt          j
        |	          g
          gddi          }t          j        |j                  }|d         rQd6}|j                            dt          j	        dt          j
        |	          g
          g,          }d%|j        d/S d-d3d/S t          | j        dd| j                   d {V  t          | j        d| j                   d| j         d7}|j                            dt          j	        dt          j
        |	          g
          gddi          }t          j        |j                  }t          | j        dd|                    dd                     d {V  t          | j        d|                    dd                     |S # t2          $ r#}t5          d8t7          |          9          d }~ww xY w):NSTARTMr>   r?   r1   u%   
            ユーザーの発言: "u  "
            
            この発言が「ポジティブ(やる気がある)」か「ネガティブ(やる気がない・不安)」か判定してください。
            
            もし「ネガティブ」なら、「目標を達成するためには、今やるしかない！」というニュアンスの厳しめの応援メッセージを作成してください。
            もし「ポジティブ」なら、「その意気だ！必ず目標は達成できる！」というニュアンスの強い称賛メッセージを作成してください。
            
            出力フォーマット(JSON):
            {
                "sentiment": "POSITIVE" or "NEGATIVE",
                "message": "作成したメッセージ"
            }
            r0   r2   r4   response_mime_typeapplication/jsonr9   r=   r'   r   rC   YOUTUBEu  "
            
            タスク: ユーザーが動画を見終わった、または次に進みたいという意思があるか判定してください。
            前の文脈で「動画見終わったら教えてね」と言っています。

            [判定基準 - **激甘(Very Lenient)**]
            1. **YES (True)**: 
               - 「はい」「うん」「ok」「OK」「みた」「見た」「次」「next」「やった」などの短い肯定。
               - 「終わった」「完了」「理解した」などの完了報告。
               - スタンプや絵文字（👍, 👌）の代わりのような短い言葉。
            2. **NO (False)**: 
               - 「まだ」「ちょっと待って」「質問がある」などの明確な否定や質問のみ。
            
            JSONで {"is_finished": true} または {"is_finished": false} を返してください。
            is_finishedz:!!! item_id is Missing -> Auto-detecting from Progress !!!r(   rE   z   -> Auto-detected item_id: z)============== [DEBUG LOG] ==============z1. Target item_id: z2. Daily Items Found: r   c                     g | ]
}|d          S )rE    .0items     rb   
<listcomp>z#chat_curriculum.<locals>.<listcomp>   s    HHHDYHHH    urlz components/ppt_viewer.html?file=z3. PPT from DB: z -> title)rE   r,   rr   z)=========================================TuH   今回はPPT資料はないみたい！次はクイズに進もうか！)rj   r'   ppts	   」と「um   
                状況: 親しい友人（Best Friend）です。
                タスク: 学習内容「u   」のPPT資料（計u   つ）を渡します。
                
                [制約]
                1. **超短文**: 「これまとめたPPT作ったから見てみて！」くらい短く。
                2. URL禁止。
                r:   r;   Fu&   OK、見終わったら教えてね！rj   r'   PPTu  "
            タスク: ユーザーがPPTを見終わったか判定。

            [判定基準 - **激甘**]
            1. **YES**: 「はい」「うん」「OK」「次」「わかった」「見た」はすべて { "is_finished": true }。
            2. **NO**: 「まだ」「質問」などは { "is_finished": false }。
            
            JSONで返してください。
            u'  
                あなたはユーザーの親しい友人（Best Friend）です。
                ユーザーがPPT学習を終えました。次は「実践クイズ（IT問題）」です。

                [メッセージ作成ルール - 厳守]
                1. **超短文**: ダラダラ話さない。「インプット完了！次はアウトプットだ！」くらいのスピード感で。
                2. **分割**: 文章を2〜3つの短い吹き出しに分け、間に「|||」を入れる。
                3. **強調**: 「**クイズ**」や「**実践**」などの単語は太字にする。
                4. **内容**: 失敗を恐れずに挑戦しよう、というポジティブなメッセージを短く。
                
                例:
                PPTお疲れ！インプットはバッチリだね！|||
                じゃあ次は、**実践クイズ**で腕試ししてみようか！|||
                間違えても大丈夫！**アウトプット**が大事だからね！
                u'   了解！見終わったら教えて！THEORYu  "
            タスク: ユーザーが理論学習を見終わったか判定。

            [判定基準 - **激甘**]
            1. **YES**: 「はい」「うん」「OK」「次」「わかった」「見た」はすべて { "is_finished": true }。
            2. **NO**: 「まだ」「質問」などは { "is_finished": false }。
            
            JSONで返してください。
            u  
                あなたはユーザーの親しい友人（Best Friend）です。
                ユーザーが資格試験の理論学習を終えました。次は「基本情報技術者試験の練習問題」です。

                [メッセージ作成ルール - 厳守]
                1. **超短文**: ダラダラ話さない。「理論バッチリ！次は問題だ！」くらいのスピード感で。
                2. **分割**: 文章を2〜3つの短い吹き出しに分け、間に「|||」を入れる。
                3. **強調**: 「**基本情報**」や「**実力試し**」などの単語は太字にする。
                4. **内容**: 理論学習を褒めて、次のFE問題へ誘導する。
                
                例:
                理論学習お疲れ！頭に入ったかな？|||
                じゃあ次は、**基本情報技術者試験**の問題に挑戦してみようか！|||
                学んだ知識が通用するか、**実力試し**だ！
                u  "
            あなたはプログラミングやITの学習をサポートする親しい友人（Best Friend）です。
            ユーザーが学習中（クイズや理論の最中）に質問やコメントをしました。
            
            [タスク]
            1. 質問であれば、わかりやすく簡潔に答えてください。
            2. ただの呟きであれば、共感して応援してください。
            3. タメ口で、親身になって明るく答えること。
            
            必ず以下のJSON形式で返してください:
            {
                "is_finished": false,
                "message": "作成したメッセージ"
            }
            rF   rG   )r   current_stepr   r@   user_messager   rO   rP   r   rQ   rR   jsonloadsr3   getrE   printr   rJ   rN   get_daily_items_and_resourceslenget_ppt_resourcesappendjoinrU   r   rL   )r#   r_   r^   r`   result_dataprompt_checkresultr@   target_item_idrW   r(   
today_infodaily_items_
valid_pptsvalid_item_namesitem_idsppt_resourcesppt	file_name
viewer_urlppt_topic_str
ppt_promptppt_msg_responsequiz_promptquiz_msg_responsefe_intro_promptfe_msg_responseprompt_fallbackra   s                                 rb   chat_curriculumr   |   s	     Q<!## 7**#w/A#TW^e^rssssssssss7-vw7KLLL%,%9  F }55(-VEJF<S<S<S;TUUUV,.@A 6  H
 *X]33K#w/A#TW^i^m^mnwy{^|^|}}}}}}}}}}7-ukooiQS6T6TUUU !Y..#w/A#TW^e^rssssssssss7-vw7KLLL%,%9  L  }55(-VEJL<Y<Y<Y;Z[[[\,.@A 6  H
 Z..Fm$ Sc$/

 ")!)VWWW0B:NNH T&.}&=%6%J:Wb%c%c
% T-7	-BN!"R."R"RSSS
 " %%6%TU_ao%p%pNK"$KBCCC<N<<===W;/Us;/?/?/?TUWWXXX  
#%  >HHKHHHH$5$G$Q$QM, > >$'J	%S	%S%S
LLL
LLMMM"))'*9~$'L#-+ +   
 )//G====BCCC
 " U,0  >H  RT  U  U  U + 0 01A B B+8 ORS]  
 $*=#A#A,#m
PZ@[@[@[?\]]]^ $B $ $  $(/4&   (-9abbb!U**#w/A#TW^e^rssssssssss7-vw7KLLL	%,%9	 	 	L }55(-VEJL<Y<Y<Y;Z[[[\,.@A 6  H
 Z..Fm$ d %+M$B$B,#m
P[@\@\@\?]^^^_ %C % %! (,8I8NOOO',9bccc
 !X--#w/A#TW^e^rssssssssss7-vw7KLLL	%,%9	 	 	L }55(-VEJL<Y<Y<Y;Z[[[\,.@A 6  H
 Z..Fm$ d# #)-"@"@,#m
P_@`@`@`?abbbc #A # # (,8LMMM',9bccc $w/A#TW^e^rssssssssss7-vw7KLLL%,%9  O  }55(-VEJO<\<\<\;]^^^_,.@A 6  H
 Z..F#w/A#TW^d^h^hirtv^w^wxxxxxxxxxx7-ufjjB6O6OPPPM < < <CFF;;;;<sM   D!\ &H1\ A:\ \ D\ '\ ,D\ ;\  D\ 
\5\00\5z
/resourcesc           	        K   	 | j         }t          j        || j                  \  }}|st	          dd          d                    d |D                       }t                              d|            t                              dt          |                      t                      }d| d	t          |           d
}|j
                            dt          j        dt          j        |          g          g          }|j        |dS # t           $ rJ}t                              t%          |                     t	          dt%          |                    d }~ww xY w)N  zSchedule not foundrG   ru   c                     g | ]
}|d          S )r,   rl   rm   s     rb   rp   z!get_resources.<locals>.<listcomp>  s    'M'M'MV'M'M'Mrq   zToday's Topics: zTotal Resources Found: us   
        状況: 親しい友人（Best Friend）です。直前の挨拶は済み。
        今日のテーマ「u   」の動画（uv  本）を紹介してください。

        [制約事項 - 厳守]
        1. **挨拶禁止**: 「おはよう」などは不可。いきなり本題へ。
        2. **超短文・簡潔**: 
           - ダラダラ説明しない。**1つの吹き出しにつき1〜2文**で短く切る。
           - 「これめっちゃ分かりやすいよ！」「〇〇の仕組みがバッチリ分かるはず！」程度でOK。
        3. **分割出力**: 「|||」で区切って2〜3つに分ける。
        4. **強調**: キーワード（「条件分岐」など）は **太字**。
        5. **URL禁止**。
        r0   r1   r2   r4   rv   )r'   	resourcesrF   )r@   r   r   rE   r   r   rV   infor   r   rO   rP   r   rQ   rR   r3   rU   r%   rL   )	r#   r@   r   r   topic_namesr_   intro_promptintro_msg_responsera   s	            rb   get_resourcesr     s     *<'
!2!PQ[]d]l!m!mY 	O S9MNNNN!&&'M'M'M'M'MNN4{44555>c)nn>>???!##) :=i..   $];;$m
8U8U8U7VWWWX < 
 
 *."
 
 	

  < < <SVVCFF;;;;<s   DD 
E(AE##E(z/quizc                   K   	 t          j        | j        | j                  }|s_t          j        | j        | j                  \  }}|r;|D ]8}|d         | j        k    rt          j        |d         | j                  }|r n9|st          dd          |S # t          $ r}|d }~wt          $ rM}t          	                    dt          |                      t          dt          |                    d }~ww xY w)NrE   r   !   問題が見つかりません。rG   zQuiz Error: rF   )r   get_quiz_problemrE   q_numr   r@   r   rU   rV   r%   rL   )r#   problemr   r   ro   hera   s          rb   get_quizr     s9     !<#4W_gmTT  	/MgN`bibqrr^[! 
( 	 	TY7?::!  1A$y/SZS`aaW 
  	^ S9\]]]]    < < <,CFF,,---CFF;;;;<s%   BB 
C?#B%%C?2AC::C?z/quiz/checkc           	      l  K   	 t                      }d| j         d| j         d| j         d| j         d	}|j                            dt          j        dt          j	        |          g	          g
          }| j
        r|t          | j
        dd| j                   d {V  t          | j
        d| j                   t          | j
        dd|j                   d {V  t          | j
        d|j                   d|j        iS # t          $ r#}t          dt!          |                    d }~ww xY w)Nu   
        あなたはプログラミング学習の採点官であり、ユーザーの親しい友人です。
        
        [問題]
        u,   
        
        [正解データ]
        u,   
        
        [解説データ]
        u2   
        
        [ユーザーの回答]
        ul  
        
        [タスク]
        ユーザーの回答が「正解データ」と一致しているか、あるいは意味的に正しいかを判定してください。
        解説データの内容を参考にして、なぜそうなるのかを補足してください。
        
        [出力ルール]
        1. 正解の場合: 「正解！さすがだね！」と褒めて、簡単に解説。
        2. 不正解の場合: 「惜しい！不正解だよ」と励まし、[解説データ]を元に正しい答えを教えてあげる。
        3. C#やJavaなどの別言語の話は絶対にしないこと。今はPythonの学習中。
        4. 口調はタメ口で。
        5. **箇条書き禁止**: 「・」「-」「*」などのリスト記号は絶対に使わないこと。すべて普通の文章（段落）で書くこと。
        r0   r1   r2   r4   rv   rf   r>   r?   r=   rC   result_messagerF   rG   )r   question_textcorrect_answerexplanationuser_answerrO   rP   r   rQ   rR   r@   r   r   r3   rU   r   rL   r#   r_   r^   r`   ra   s        rb   
check_quizr     s     -<!## 
		  
	  
	  
	  6 =11$m
8O8O8O7PQQQR 2 
 
  	E#w/A#TW^e^qrrrrrrrrrr7-vw7JKKK#w/A#TW^f^kllllllllll7-uhmDDD (-00 < < <CFF;;;;<s   DD 
D3D..D3z/ppt/{file_name}r   c                    K   t           }t          j                            ||           }t          j                            |          rt          || d          S t          dd          )u   
    프론트엔드 URL: /goal-skill-t/api/file/ppt/item_18.pptx
    실제 서버 경로: /home/air/goalskill_t/back/PPT/item_18.pptx
    zIapplication/vnd.openxmlformats-officedocument.presentationml.presentation)pathfilename
media_typer   zFile not found on serverrG   )r   osr   r   existsr   r   )r   base_dir	file_paths      rb   get_ppt_filer     sq       HXy11I 
w~~i   	Pb	
 
 
 	
 4NOOOOrq   z/ppt/slides/{file_name}c           	        K   ddl m} ddlm}m}m} ddlm} t          j	        
                    t          |           }t          j	                            |          st          dd          	  ||          }g }|j        }	|j        }
t!          |j                  D ]\  }}|dz   g d	}|j        D ]}d
di}|j        r\g }|j        j        D ]}g }|j        D ]}d|j        i}|j        j        rd|d<   |j        j        r|j        j        j        |d<   |j        j        r2|j        j        j        r!t=          |j        j        j                  |d<   |                    |           |s|j                                         r=||j        d}|j!        t=          |j!                  |d<   |                    |           d||j"        r|j"        |	z  dz  nd|j#        r|j#        |
z  dz  nd|j$        r|j$        |	z  dz  nd|j%        r|j%        |
z  dz  ndd}nC|j&        r<g }|j'        j(        D ](}d |j)        D             }|                    |           )d|d}|d
         dk    r|d                             |           |                    |           | tU          |          |dS # tV          $ r&}t          ddt=          |                     d}~ww xY w)u>   PPTXファイルのスライド内容をJSON形式で返すAPIr   )Presentation)InchesPtEmu)RGBColorr   zPPT file not foundrG      )	slide_numelementstypeunknownr3   TboldfontSizecolor)runsr3   Nalignd   
   )r   
paragraphslefttopwidthheightc                     g | ]	}|j         
S rl   r2   )rn   cells     rb   rp   z"get_ppt_slides.<locals>.<listcomp>e  s     A A At A A Arq   table)r   rowsr   )filetotal_slidesslidesrF   zPPT parse error: ),pptxr   	pptx.utilr   r   r   pptx.dml.colorr   r   r   r   r   r   r   slide_widthslide_height	enumerater   shapeshas_text_frame
text_framer   r   r3   fontr   sizeptr   rgbrL   r   strip	alignmentr   r   r   r   	has_tabler   r   cellsr   rU   )r   r   r   r   r   r   r   prsslides_datar   r   	slide_idxslide
slide_infoshapeelementr   parar   runrun_data	para_data
table_datarowr   ra   s                             rb   get_ppt_slidesr   ,  s      "!!!!!))))))))))''''''Xy11I7>>)$$ J4HIIII=Rl9%% o' )#* 5 5 -	+ -	+Iu'01}"EEJ (; (;!9-' "D!#J % 0 ; 9 9!#'9 2 2C(.'9H"x} 837 0"x} H7:x}7G 4"x~ L#(.2D L478J4K4K 1 KK1111 949??#4#4 915ty(I(II#~9585H5H	' 2&--i888 !'&0BG* S
[ 83 > >RSAFQuy<7#==PQDIK!X{!:S!@!@UXGL|"[%,"="C"CY[ GG _ D!#J${/ 1 1 A Asy A A A"))%0000'.
CCG6?i//z*11':::z**** ,,!
 
 	

  R R R4PA4P4PQQQQRs   /IJ4 4
K$>!KK$z/theory/datac                   K   	 | j         }t          j        |          }|st          dd          |d         }t          j        ||          }|s3|dz
  dz  dz   }|dk    rt          j        ||          }|rdd	|d
S dddS t          j        d|d                   }|sdddS t          |	                    d                    }|d         }	|	dk    rd	d	|d         |dS t          j
                            |d                   }
t          j        ||
          }|sdddS |D ]W}|                    d          r@|d         r8t          j                            |d                   }dt            d| d| |d<   Xi }|D ]>}|d         }||vr||d         g d||<   ||         d                             |           ?d	d|d         |t%          |                                          t)          |          dS # t          $ r}|d}~wt*          $ r@}t,                              d|            t          d t1          |                    d}~ww xY w)!uK   현재 일차의 CERT 아이템에 맞는 이론/문제 데이터를 조회r   Progress not foundrG   r(   r         FT)foundreview_modechaptersu-   今日は資格試験の学習はないよ！r   r'   u   第(\d+)章r,   u0   チャプター情報が見つかりません。	item_typePRACTICE)r   practice_only	cert_namesectionrE   )	sub_rangeu*   理論データが見つかりません。img//api/file/theory-img/sectionchapter
main_titler  r  itemsr  )r   r  r  r  r   total_itemsNzTheory Data Error: rF   )r@   r   rJ   r   get_cert_item_for_dayget_cert_chapters_for_monthresearchintgroupTHEORY_SUB_RANGESr~   get_theory_datar   r   basenamer   r   listvaluesr   rU   rV   r%   rL   )r#   r@   rW   r(   	cert_item
sort_orderr   matchsection_numr  r  theory_itemsro   img_filenamechr   ra   s                    rb   
get_theoryr"  y  s     N<'
 %6zBB 	NC8LMMMM}- &;JTT	 	`&?b0A5JR,HU`aa W%*4XVVV"/^___ 	.)F*;<< 	c"/abbb%++a..))k*	 
""!%&v.&	   &7;;Ii<PQQ	(8PYZZZ 	]"/[\\\ ! 	g 	gDxx g4; g!w//U<<f*ff+ffXdffU   	/ 	/DiB!!!"&|"4   
 RL!((.... ""6*"X__..//|,,
 
 	
     < < <.1..///CFF;;;;<sD   A:G= ?G= !G= &<G= #AG= %CG= =
IH		I;IIz/cert/review/chaptersc                 <  K   	 | j         }t          j        |          }|st          dd          t          j        ||d                   }d|iS # t
          $ r@}t                              d|            t          dt          |                    d}~ww xY w)	uA   13~20일차 복습 모드: 해당 월에 배운 장 목록 반환r   r   rG   r(   r   zReview Chapters Error: rF   N)	r@   r   rJ   r   r  rU   rV   r%   rL   )r#   r@   rW   r   ra   s        rb   get_review_chaptersr$    s      
<'
$6zBB 	NC8LMMMM$@XVcMdeeH%% < < <2q22333CFF;;;;<s   AA 
B;BB)	BaseModelc                       e Zd ZU eed<   dS )TheoryIntroRequestr  N__name__
__module____qualname__rL   __annotations__rl   rq   rb   r'  r'    s         NNNNNrq   r'  z/theory/introc           	      x  K   	 t                      }d| j         d| j         d| j         d}|j                            dt	          j        dt	          j        |          g          g	          }d
|j        iS # t          $ r4}t          
                    d|            d
d| j         dicY d}~S d}~ww xY w)u1   자격증 이론 소개 메시지를 AI로 생성u   
        あなたはユーザーの親しい友人（Best Friend）です。
        ユーザーが実践クイズを終え、次は資格試験の理論学習「u   」に入ります。

        [メッセージ作成ルール - 厳守]
        1. **超短文**: 2〜3つの短い吹き出しに分け、間に「|||」を入れる。
        2. **強調**: 「**資格試験**」「**理論学習**」「**u  **」などの重要ワードは**太字**にする。
        3. **口調**: 敬語禁止。タメ口で明るく。絵文字1〜2個使用。
        4. **内容**: クイズお疲れ → 次は理論学習だよ → チャプター名を紹介。
        5. **絶対に4つ以上の吹き出しにしない**。3つまで。

        例:
        クイズお疲れ！💪|||次は、**資格試験の理論学習**だよ！|||「**u,   **」の内容を確認しよう！
        r0   r1   r2   r4   rv   r'   zTheory Intro Error: uX   クイズお疲れ！💪✨|||次は、**資格試験の理論学習**だよ！|||「**u#   **」の内容を確認しよう！N)r   r  rO   rP   r   rQ   rR   r3   rU   rV   r%   r   s        rb   get_theory_intror.    s=     n!##W^Wh  JQIZ  _f^o   =11$m
8O8O8O7PQQQR 2 
 
 8=)) n n n/A//000  mv}  wH  m  m  m  n  	n  	n  	n  	n  	n  	nns   A6A; ;
B9)B4.B94B9z/theory/section/{section_num}r  c                   K   	 t          j        |           }|st          dd          |D ]W}|                    d          r@|d         r8t          j                            |d                   }dt           d|  d| |d<   Xi }|D ]>}|d         }||vr||d         g d	||<   ||         d
                             |           ?d| t          |
                                          t          |          dS # t          $ r}|d}~wt          $ r@}t                              d|            t          dt          |                    d}~ww xY w)uB   섹션 번호로 직접 이론 데이터 조회 (복습 모드용)r   zTheory data not foundrG   r  r	  r
  r  r  r  r  T)r   r  r   r  NzTheory Section Error: rF   )r   r  r   r~   r   r   r  r   r   r  r  r   rU   rV   r%   rL   )r  r  ro   r   r   r!  r   ra   s           rb   get_theory_sectionr0    s     <(8EE 	QC8OPPPP ! 	g 	gDxx g4; g!w//U<<f*ff+ffXdffU   	/ 	/DiB!!+-T,=OZ\]]RL!((.... "X__..//|,,	
 
 	
     < < <1a11222CFF;;;;<s$   C6C; ;
EDE;EEz /theory-img/{section}/{filename}r  r   c                    K   t           j                            t          | |          }t           j                            |          rt          |d          S t          dd          )u   이론 이미지 파일 서빙z	image/png)r   r   r   Image not foundrG   )r   r   r   r   r   r   r   )r  r   r   s      rb   get_theory_imager3    s]       Xw99I	w~~i   G{CCCC4EFFFFrq   z	/fe/introc            	      $  K   	 t                      } d}| j                            dt          j        dt          j        |          g          g          }d|j        iS # t          $ r#}t          dt          |          	          d }~ww xY w)
Nu  
        あなたはユーザーの親しい友人です。
        ユーザーがPythonの課題をクリアしました。次は「基本情報技術者試験」の練習問題です。
        
        以下のルールでメッセージを作成してください：
        1. **分割**: 文章を2〜3つの短いフレーズに分け、間に「|||」を入れる。
        2. **短文**: 1つの吹き出しは短く簡潔に。「次はこれだ！」というスピード感で。
        3. **強調**: 「**基本情報**」や「**実力試し**」などは太字にする。
        4. **内容**: Pythonクリアを褒めて、次のFE問題へ誘導する。
        
        例:
        お疲れ！Python完走だね！さすが！|||
        じゃあ次は、**基本情報技術者試験**の問題に挑戦してみようか！|||
        学んだ知識が通用するか、**実力試し**だ！
        r0   r1   r2   r4   rv   r'   rF   rG   
r   rO   rP   r   rQ   rR   r3   rU   r   rL   r_   r^   r`   ra   s       rb   get_fe_intror7  '  s      <!## =11$m
8O8O8O7PQQQR 2 
 
 8=)) < < <CFF;;;;<   AA" "
B,B

Bz/fe/quizc                 T  K   	 t          j                    }t          j        | j                  }|st	          dd          | j        |k    |d<   |S # t
          $ rJ}t                              t          |                     t	          dt          |                    d }~ww xY w)Nr   r   rG   is_lastrF   )	r   get_fe_problem_countget_fe_problem_detailr   r   rU   rV   r%   rL   )r#   total_countr   ra   s       rb   get_fe_quizr>  E  s      <'<>>#9'-HH 	^ S9\]]]] &m{:	 < < <SVVCFF;;;;<s   AA 
B'AB""B'z/fe/quiz/checkc                    K   	 t          j        | j        | j                  }|S # t          $ r#}t          dt          |                    d }~ww xY w)NrF   rG   )r   check_fe_answer_logicquestion_numberr   rU   r   rL   r#   r   ra   s      rb   check_fe_quizrC  X  sa      <"89PRYReff < < <CFF;;;;<s    % 
AAAz
/cert/quizc                 6  K   	 t          j        | j                  }t          j        | j        | j                  }|st          dd          | j        |k    |d<   ||d<   |                    d          rF|d         r>|d                             d          d         }d	| j         }dt           d
| d| |d<   |S # t
          $ r}|d}~wt          $ r@}t                              d|            t          dt          |                    d}~ww xY w)u&   챕터별 cert_questions 문제 조회r   r   rG   r:  r=  question_imgr	  r  /api/file/cert-img/Nzcert quiz error: rF   )r   get_cert_question_countr  get_cert_question_detailr   r   r~   splitr   rU   rV   r%   rL   )r#   r=  r   r   section_dirr   ra   s          rb   get_cert_quizrL  b  sQ     <'?PP#<W_gm\\ 	]C8[\\\\%m{:	!, ;;~&& 	b7>+B 	b~.44S99"=H5GO55K&a*&a&a&a&aW_&a&aGN#    < < <,,,---CFF;;;;<s$   B:B? ?
D	CD;DDz/cert/quiz/checkc                   K   	 t          j        | j        | j        | j                  }|                    d          dk    rS|                    d          r>|d                             d          d         }d| j         }dt           d| d| |d<   |S # t          $ r@}t          
                    d|            t          d	t          |          
          d}~ww xY w)u%   cert_questions 정답 확인 + 해설explanation_typer  r   r	  rF  r  rG  zcert quiz check error: rF   rG   N)r   check_cert_answerr  rA  r   r~   rJ  r   rU   rV   r%   r   rL   )r#   r   r   rK  ra   s        rb   check_cert_quizrP  |  s      <"4W_gF]_f_rss ::())U22vzz-7P7P2m,22377;H5GO55K$_
$_$_{$_$_U]$_$_F=! < < <2q22333CFF;;;;<s   BB 
C!!;CC!z/cert-img/{section}/{filename}c                 >  K   ddl m} ddl}|j                            t
          | |          }|j                            |          s!|j                            t          | |          }|j                            |          st          dd           ||          S )uC   cert_questions 관련 이미지 서빙 (question_img, solution_img)r   r   Nr   r2  rG   )	fastapi.responsesr   r   r   r   r   r   r   r   )r  r   r   r   img_paths        rb   get_cert_imgrT    s       /.....IIIw||L'8<<H7>>(## ?7<<
GX>>7>>(## G4EFFFF<!!!rq   z/fe/completec            	      $  K   	 t                      } d}| j                            dt          j        dt          j        |          g          g          }d|j        iS # t          $ r#}t          dt          |          	          d }~ww xY w)
Nu?  
        ユーザーが基本情報技術者試験（FE）の難しい問題をすべてクリアしました。
        親しい友人として、最高の称賛を送ってください。

        [制約事項 - 厳守]
        1. **超短文**: 長い文章は禁止。テンポよく短く。「マジですごい！」「天才かよ！」など。
        2. **分割**: メッセージを2〜3つの短い吹き出しに分けるため、間に「|||」を入れる。
        3. **強調**: 「**完走**」「**すごい**」「**デバッグ日誌**」などの重要単語は太字にする。
        4. **内容**: 
           - まず完走したことを手放しで褒める。
           - 最後に「今日の学びを忘れないように、**デバッグ日誌**を書こう！」と提案する。
        r0   r1   r2   r4   rv   r'   rF   rG   r5  r6  s       rb   complete_fe_phaserV    s      <!## =11$m
8O8O8O7PQQQR 2 
 
 8=)) < < <CFF;;;;<r8  z/journal/chatc           	      H  K   	 t                      }| j        pg }| j        }|dk    rd}|j                            dt          j        dt          j        |          g          g          }t          | j	        dd	|j
        
           d {V  t          | j	        d|j
                   d|j
        dS t          |          }|dk    rd| d}|j                            dt          j        dt          j        |          g          g          }t          | j	        dd	|
           d {V  t          | j	        d|           t          | j	        dd	|j
        
           d {V  t          | j	        d|j
                   d|j
        dS |dk    rd| d}|j                            dt          j        dt          j        |          g          g          }t          | j	        dd	|
           d {V  t          | j	        d|           t          | j	        dd	|j
        
           d {V  t          | j	        d|j
                   d|j
        dS |dk    rd| d}	|j                            dt          j        dt          j        |	          g          g          }t          | j	        dd	|
           d {V  t          | j	        d|           t          | j	        dd	|j
        
           d {V  t          | j	        d|j
                   d|j
        dS d| d}
|j                            dt          j        dt          j        |
          g          g          }t          | j	        dd	|
           d {V  t          | j	        d|           t          | j	        dd	|j
        
           d {V  t          | j	        d|j
                   d|j
        dS # t          $ r#}t          dt          |                    d }~ww xY w)Nu   日誌作成を始めようu
  
            あなたはユーザーの親しい友人（Best Friend）です。
            今からユーザーと一緒に「学習日誌（デバッグ日誌）」を作成します。
            
            [タスク]
            最初の質問をしてください。
            「よし、日誌書こうか！今日の勉強、どんな感じだった？印象に残ってることとか、進捗はどうかな？」
            というニュアンスで、明るく聞いてください。
            r0   r1   r2   r4   rv   r=   r>   r?   rC   Frw      u%   
            ユーザーの回答: "u  "
            あなたは親しい友人です。ユーザーが今日の感想を言いました。
            
            [タスク]
            1. まず共感してください（「そっか、楽しかったんだね！」「大変だったね」など）。
            2. 次に、「具体的にどこか詰まっちゃったところとか、エラーが出たところはあった？どんなことでも教えて！」と聞いてください。
            rf      u  "
            あなたは親しい友人です。ユーザーが「難しかった場所」や「エラー」について答えました。

            [制約事項 - **深掘り禁止(Do Not Dig Deeper)**]
            1. **即座に受容**: 回答が短くても、具体的でなくても、「そっか、そこが難しかったんだね」とすぐに受け入れてください。
            2. **質問禁止**: 「具体的にどんなエラー？」「どう解決した？」と**聞き返さないでください**。
            3. **次の話題へ**: すぐに「そういう時、何か参考にした動画とか資料とかはあったかな？」と次の質問に進んでください。
               u  "
            あなたは親しい友人です。ユーザーが参考にした資料について答えました。
            
            [タスク]
            1. 「おお、それを見て頑張ったんだね！」と褒める。
            2. 最後に「その動画とかを見て、最終的に問題は解決できたかな？今はどんな気持ち？」と聞いて、締めくくりの準備をして。
            ui  "
            あなたは親しい友人です。これでインタビューは終了です。
            
            [タスク]
            1. 「よし！これで今日の日誌はバッチリだね！」と明るく締める。
            2. 「ゆっくり休んでね！」と労う。
            3. これ以上の質問はしない。
            TrF   rG   )r   historyr{   rO   rP   r   rQ   rR   r   r@   r3   r   r   rU   r   rL   )r#   r_   r[  
user_inputstart_promptr`   
turn_countstep_1_promptstep_2_promptstep_3_promptfinal_promptra   s               rb   chat_journalrc    s6     s<!##/'R)
 666L }55(-VEJL<Y<Y<Y;Z[[[\ 6  H
 $w/A#TW^f^kllllllllll7-uhmDDD#(X]CCC \\
 ??%/  M }55(-VEJM<Z<Z<Z;[\\\] 6  H
 $w/A#TW^hiiiiiiiiii7-vzBBB#w/A#TW^f^kllllllllll7-uhmDDD#(X]CCC 1__%/  M }55(-VEJM<Z<Z<Z;[\\\] 6  H
 $w/A#TW^hiiiiiiiiii7-vzBBB#w/A#TW^f^kllllllllll7-uhmDDD#(X]CCC 1__%/  M }55(-VEJM<Z<Z<Z;[\\\] 6  H
 $w/A#TW^hiiiiiiiiii7-vzBBB#w/A#TW^f^kllllllllll7-uhmDDD#(X]CCC%/  L }55(-VEJL<Y<Y<Y;Z[[[\ 6  H
 $w/A#TW^hiiiiiiiiii7-vzBBB#w/A#TW^f^kllllllllll7-uhmDDD#'HMBBB < < <CFF;;;;<s4   B2O4 7CO4 CO4  CO4 -CO4 4
P!>PP!z/journal/generatec           	        K   	 t                      }t          j        | j                  }|r|d         nd}d                    d | j        D                       }d| d}|j                            dt          j	        dt          j
        |	          g
          gddi          }t          j        |j                  }t          j        | j        ||d         |d         |d         |d                   }|d          d|d          d|d          }	t          | j        dd|	           d {V  t!          | j        d|	           |st#          d          ddlm}
 |dz   } |
| j        |           	 t          j        | j        |           n4# t"          $ r'}t*                              d|            Y d }~nd }~ww xY w	 t          j        | j                   n4# t"          $ r'}t*                              d|            Y d }~nd }~ww xY wd|dS # t"          $ rJ}t*                              t1          |                     t3          dt1          |                    d }~ww xY w) Nr(   r   
c                 4    g | ]}|d           d|d          S )r5   z: r3   rl   )rn   entrys     rb   rp   z$generate_journal.<locals>.<listcomp>p  s.    &u&u&uu%-'J'J5='J'J&u&u&urq   u   
        以下のユーザーとの会話ログを分析し、学習の振り返りデータを作成してください。
        
        [会話ログ]
        u!  
        
        [タスク]
        1. **summary_content**: 会話内容を元に、指定されたMarkdown形式で「デバッグ日誌」を作成する。
           形式例:
           #### 📅 **今日のデバッグ日誌 | Topic: ...**
           * **🔍状況把握:** ...
           * **📓 デバッグ:** ...
           * **💡PPT & YouTube:** ...
           * **🛠 解決策:** ...
           
        2. **understanding_score**: 今日のユーザーの理解度を 0〜100 の整数で評価する。
        3. **ai_feedback**: 学習内容に対する具体的なフィードバック（改善点やアドバイス）を親しい口調で書く。
        4. **praise_content**: 今日の頑張りを褒め称える言葉（「今日の称賛」）を書く。
        
        出力は必ず以下のJSONフォーマットのみにしてください：
        {
            "summary_content": "...",
            "understanding_score": 85,
            "ai_feedback": "...",
            "praise_content": "..."
        }
        r0   r1   r2   r4   rg   rh   r9   r-   understanding_scorer.   r/    r=   r>   r?   rC   zDB Save Failedr   )create_result_rowz"Category Progress Update Warning: zFile Update Warning: success)r&   dayrF   rG   )r   r   rJ   r@   r   conversation_historyrO   rP   r   rQ   rR   r|   r}   r3   save_debug_journalr   r   rU   app.models.goalskill_modulerj  update_category_progressrV   r%   update_progress_excel_and_pdfrL   r   )r#   r_   rW   r(   conversation_textr^   r`   r   savedjournal_textrj  next_dayprog_efile_era   s                  rb   generate_journalrx  f  s     U<!## %6w7IJJ19@h}--q !II&u&uX_Xt&u&u&uvv 
	  8 =11$m
8O8O8O7PQQQR(*<= 2 
 
 HM** "4$%()=!#$
 
 !!23hhf]6KhhfUeNfhh7+=cPSZfggggggggggw)5,??? 	.,--- 	BAAAAA?',h777	H6w7I;WWWW 	H 	H 	HLLFfFFGGGGGGGG	H	;;G<NOOOO 	; 	; 	;LL999::::::::	; $H555 < < <SVVCFF;;;;<sm   E1H 6F H 
GF=8H =GH G  H  
H*HH HH 
I-#AI((I-z/journal/viewc                 H  K   	 t          j        | j                  }|r|d         nd}t          j        | j        |          }|s#|dk    rt          j        | j        |dz
            }|sdddS d|dS # t          $ r#}t          dt          |          	          d }~ww xY w)
Nr(   r   Fu!   日誌が見つかりません。r  T)r   datarF   rG   )r   rJ   r@   get_debug_journalrU   r   rL   )r#   rW   r(   journalra   s        rb   view_journalr}    s      <$6w7IJJ19@h}--q $5g6H+VV 	_;??'9':Lk\]o^^G 	T"/RSSSw/// < < <CFF;;;;<s   A*A4 /A4 4
B!>BB!z/journal/history/{session_id}r@   c                   K   	 t          j        |           }|sdg dS g }|D ]S}|d         r|d                             d          nd}|                    ||d         |d         |d         d	           Tt	          |          |dS # t
          $ rJ}t                              t          |                     t          d
t          |                    d }~ww xY w)Nr   )countrz  
created_atz%Y-%m-%dUnknownr-   r.   r/   )dater-   r.   r/   rF   rG   )
r   get_all_debug_journalsstrftimer   r   rU   rV   r%   rL   r   )r@   r[  rz  r   date_strra   s         rb   get_journal_historyr    s     <#::FF 	,+++  	 	CAD\ARas<(11*===XaHKK #&'8#9"=1"%&6"7	      TD111 < < <SVVCFF;;;;<s   B	 A)B	 	
CACCz/progress/{session_id}c                    K   	 t          j        |           }d|iS # t          $ r@}t                              d|            t          dt          |                    d}~ww xY w)u6   ユーザーのカテゴリ別学習進捗率を取得rW   zProgress Error: rF   rG   N)r   get_category_progressrU   rV   r%   r   rL   r@   rz  ra   s      rb   get_progressr    sy      < 6zBBD!! < < <+++,,,CFF;;;;<    
A&;A!!A&z/plan/{session_id}c                    K   	 t          j        |           }d|iS # t          $ r@}t                              d|            t          dt          |                    d}~ww xY w)uK   ユーザーのカリキュラム計画（ガントチャート）を取得planzPlan Error: rF   rG   N)r   get_curriculum_planrU   rV   r%   r   rL   r  s      rb   get_planr    sx      < 4Z@@~ < < <'A''(((CFF;;;;<r  z/curriculum_pdf/{session_id}c                    K   t           }d|  d}t          j                            ||          }t          j                            |          rt          ||dd          S t          dd          )	zA
    URL: /goal-skill-t/api/file/curriculum_pdf/{session_id}
    curriculum_.pdfapplication/pdfinliner   r   r   content_disposition_typer   zCurriculum PDF not foundrG   )r   r   r   r   r   r   r   r@   r   r   r   s       rb   get_curriculum_pdfr     s       #H.j...IXy11I 
w~~i   P(%-	
 
 
 	
 4NOOOOrq   z/progress_pdf/{session_id}c                    K   t           }d|  d}t          j                            ||          }t          j                            |          rt          ||dd          S t          dd          )	z?
    URL: /goal-skill-t/api/file/progress_pdf/{session_id}
    	progress_r  r  r  r  r   zProgress PDF not foundrG   )r   r   r   r   r   r   r   r  s       rb   get_progress_pdfr    s       !H,J,,,IXy11I 
w~~i   N(%-	
 
 
 	
 4LMMMMrq   c                       e Zd ZU eed<   dS )GenerateCurriculumRequestr@   Nr(  rl   rq   rb   r  r  0  s         OOOOOrq   r  z	/generatec                 `  K   	 t                               d| j                    t          | j                   d{V }|d         rd|d         |d         dS d|d         ddS # t          $ r=}t                               d	|            dd
t          |           ddcY d}~S d}~ww xY w)u   
    ユーザープロフィールを基にAIでパーソナライズされたカリキュラムを生成します。
    既存のuser_curriculumを削除し、AI生成の新しいカリキュラムで置き換えます。
    z"[Generate] AI Curriculum request: Nrk  r'   
item_count)r&   r'   r  r%   r   z[Generate] Error: u    カリキュラム生成失敗: )rV   r   r@   r   rU   r%   rL   rB  s      rb   generate_curriculumr  3  s     
M9KMMNNN-g.@AAAAAAAA) 	#!),$\2   "!),  
  
 
 
-!--...B#a&&BB
 
 	
 	
 	
 	
 	
 	

s$   AA& A& &
B-02B("B-(B-)Rfastapir   r   
app.modelsr   app.models.ai_curriculum_moduler   app.schemas.curriculum_schemar   r   r	   r
   r   r   r   r   r   app.core.configr   r   r   r   r   r   r   r   r  !app.services.goalskill_classifierr   app.models.report_db_moduler   google.genair   r|   r   loggingrR  r   basicConfigINFO	getLoggerr)  rV   routerfile_routerrT   postrc   r   r   r   r   r~   rL   r   r   r"  r$  pydanticr%  r'  r.  r  r0  r3  r7  r>  rC  rL  rP  rT  rV  rc  rx  r}  r  r  r  r  r  r  r  rl   rq   rb   <module>r     s   , , , , , , , , ( ( ( ( ( ( B B B B B B `  `  `  `  `  `  `  `  `  `  `  `  `  `  `  `  `  `  `  `  `  ` O  O  O  O  O  O  O  O  O  O  O  O  O  O  O  O  O  O  O  O 				 ? ? ? ? ? ? 6 6 6 6 6 6        				  * * * * * *  ', ' ' ' '		8	$	$	

 
 
 i
  
 XO<$: O< O< O< O<b WR<#8 R< R< R< R<h \+< +< +< +< +<Z W"<N "< "< "< "<H ].<. .< .< .< .<b #$$P# P P P %$P* %&&GRC GR GR GR '&GRX ^P<4 P< P< P< P<d $%%<'= < < < &%<              _n$6 n n n n6 +,,<# < < < -,<B 344GC G3 G G G 54G [< < <: Z<~ < < < <$ <!3 < < < < \< < < < <2   <#7 < < < ! <  122
" 
"s 
" 
" 
" 32
" ^< < <f _t< 5 t< t< t< t<n  !!V<$: V< V< V< "!V<p _< 1 < < < <$ +,,<# < < < -,<0 $%%<3 < < < &%<  !!<s < < < "!< /00P P P P 10P* -..Ns N N N /.N2    	    [
'@ 
 
 
 
 
 
rq   